h5新特性
1. 新增选择器:querySelector、querySelectorAll
2. 拖拽功能:drag和drop
3. 媒体播放:video和audio
4. 本地存储:localStorage和sessionStorage
5. 语义化标签:article、footer、header、nav、section
6. 增强表单控件:calendar、date、time、email、url、search
7. 地理位置:geolocation
8. 多任务:webworker
9. 全双工通信:websocket
10. 历史管理:history
11. 跨域资源共享:CORS
12. 跨窗口通信:postMessage
13. Form Data对象
14. 绘画:canvas
伪元素和伪类
伪类:为已有元素处于某种状态时添加样式。如:hover
伪元素:创建一些不在dom树中的元素并添加样式。如:before
<title> <!--:页面主体内容。-->
<hn> <!--:h1~h6,分级标题,<h1> 与 <title> 协调有利于搜索引擎优化。-->
<ul> <!--:无序列表。-->
<li> <!--:有序列表。-->
<header> <!--:页眉通常包括网站标志、主导航、全站链接以及搜索框。-->
<nav> <!--:标记导航,仅对文档中重要的链接群使用。-->
<main> <!--:页面主要内容,一个页面只能使用一次。如果是web应用,则包围其主要功能。-->
<article> <!--:定义外部的内容,其中的内容独立于文档的其余部分。-->
<section> <!--:定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。-->
<aside> <!--:定义其所处内容之外的内容。如侧栏、文章的一组链接、广告、友情链接、相关产品列表等。-->
<footer> <!--:页脚,只有当父级是body时,才是整个页面的页脚。-->
<small> <!--:呈现小号字体效果,指定细则,输入免责声明、注解、署名、版权。-->
<strong> <!--:和 em 标签一样,用于强调文本,但它强调的程度更强一些。-->
<em> <!--:将其中的文本表示为强调的内容,表现为斜体。-->
<mark> <!--:使用黄色突出显示部分文本。-->
<figure> <!--:规定独立的流内容(图像、图表、照片、代码等等)(默认有40px左右margin)。-->
<figcaption><!--:定义 figure 元素的标题,应该被置于 figure 元素的第一个或最后一个子元素的位置。-->
<cite> <!--:表示所包含的文本对某个参考文献的引用,比如书籍或者杂志的标题。-->
<blockquoto><!--:定义块引用,块引用拥有它们自己的空间。-->
<q> <!--:短的引述(跨浏览器问题,尽量避免使用)。-->
<time> <!--:datetime属性遵循特定格式,如果忽略此属性,文本内容必须是合法的日期或者时间格式。-->
<abbr> <!--:简称或缩写。-->
<dfn> <!--:定义术语元素,与定义必须紧挨着,可以在描述列表dl元素中使用。-->
<address> <!--:作者、相关人士或组织的联系信息(电子邮件地址、指向联系信息页的链接)。-->
<del> <!--:移除的内容。-->
<ins> <!--:添加的内容。-->
<code> <!--:标记代码。-->
<meter> <!--:定义已知范围或分数值内的标量测量。(Internet Explorer 不支持 meter 标签)-->
<progress> <!--:定义运行中的进度(进程)。-->
语义化优点
1. 易于用户阅读,样式丢失也可以呈现清晰的结构
2. 利于SEO
3. 方便屏幕阅读器解析
4. 利于开发和维护
audio标签api
常用属性
src url地址
preload 预加载
loop 循环播放
controls 是否显示控制条
autoplay 自动播放
常用事件
play 播放
pause 暂停
ended 播放结束
let const var
var ES5变量声明方式,默认值为undefined,方法作用域
let ES6变量声明方式,声明前访问报错,禁止重复,块作用域
const ES6变量声明方式,声明常量,必须初始化,变量的内存地址不能改动。
js数据类型
基本数据类型:
Number、String、Boolean、null、undefined、symbol、bigint
引用数据类型:
object,function
object:普通对象、日期对象、正则对象、数组对象、Math对象
存储:
基本数据类型存储在栈中,占据空间小,大小固定。
引用数据类型存储在堆中,占据空间大,大小不固定。引用数据类型在栈中存储了指针,指向堆中的真实数据。
Object.assign
Object.assign 可以实现对象的合并
Object.assign(target, ...sources) 将souce里面的对象的属性复制到target,如果已存在会覆盖。后续的souce会覆盖签名的source。
constructor
每个函数都有一个prototype属性,它指向原型对象。所有原型对象都有constructor属性,它指向prototype属性所在函数。
当调用constructor函数创建一个实例后,该实例的__proto__,指向该函数的原型对象。
map和forEach的区别
相同点:
1. 都是循环遍历数组的每一项
2. 每次执行匿名函数都有三个参数:item(当前项)、index(当前索引)、arr(原数组)
3. 匿名函数的this指向window
4. 只能遍历数组
区别:
1. map会分配内存空间存储新数组并返回,forEach不会
2. forEach允许callback修改原数组。map返回新的数组。
for…of
可以遍历具有属性iterator的对象。
包括:Array,Map,Set,String。
js静态类型检查
js是动态类型语言。
静态类型语言:类型检查发生在编译阶段。
动态类型语言:运行时错误才会被发现。
TypeScript
静态类型的优势:
1. 可以尽早发现错误。
2. 减少复杂的错误处理。
3. 将数据和行为分离。
4. 减少单元测试的数量。
缺点:
1. 代码冗长。
2. 需要掌握类型
indexof
str.indexOf(searchValue [, fromIndex])
查找字符串位置。
如果没有找到返回 -1
iframe
优点:
1. iframe能原封不动的把签入的网页展现出来。
2. 样式隔离。
缺点:
1. 阻塞主页的load事件;
2. iframe和主页共享连接池。影响页面的并行加载;
3. 不利于SEO;
4. 增加http请求;
5. 无法保留历史记录。
变量提升
js是单线程语言,执行是顺序执行。但不是逐行分析和执行。会先进行编译阶段,然后是执行阶段。
编译阶段在代码执行前几毫秒,会检查所有变量和函数声明,所有函数和变量声明会被添加到内存。所以这些函数和变量能在它们真正被使用前使用。
作用域
作用域是一个独立的块,确保里面的变量和函数不会泄漏,有全局作用域和函数作用域。
ES6 新增块作用域
HashMap和ArrayMap区别
1. 查找效率:
HashMap因为根据hashcode算出index,查找效率会随着数组长度增加而增加;
ArrayMap使用二分查找,所以当数组长度增加1倍时,就要多进行一次判断,效率下降。
2. 扩容数量
HashMap初始值16,每次扩容翻倍。
ArrayMap
Web Components
Web Components组件化开发,最初的目的是代码重用,功能相对单一或者独立。
使用方式:创建一个类或函数来指定组件的功能。
js中arguments
在js中调用函数时,传入函数的参数会被存到一个叫做arguments的对象里面。
js中每个函数都有一个Arguments对象实例arguments
instanceOf 原理
instanceOf 判断一个实例是否属于某种类型。
a instanceOf B 要求 a的原型链上的某个原型对象为 B的原型对象
数组去重
1. 利用ES6 Set去重
Array.from(new Set(arr))
2. 利用for嵌套for,然后splice去重
for(var i=0; i<arr.length; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
arr.splice(j,1);
j--;
}
}
}
3. 利用indexOf去重
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array.indexOf(arr[i]) === -1) {
array.push(arr[i])
}
}
4. 利用sort()
arr = arr.sort()
var arrry= [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
5. 利用includes
var array =[];
for(var i = 0; i < arr.length; i++) {
if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
array.push(arr[i]);
}
}
return array
6. 利用filter
arr.filter(function(item, index, arr) {
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index;
});
7. 利用递归去重
8. 利用Map数据结构去重
let map = new Map();
let array = new Array(); // 数组用于返回结果
for (let i = 0; i < arr.length; i++) {
if(map.has(arr[i])) { // 如果有该key值
map.set(arr[i], true);
} else {
map.set(arr[i], false); // 如果没有该key值
array.push(arr[i]);
}
}
9. 利用reduce+includes
arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[])
10. [...new Set(arr)]
for配合includes、for+filter、for+indexOf、for+sort、reduce配合includes、Array.for+set、for+map、...+set、双重for、递归
编码和字符集的区别
字符集是字母和符号的集合;编码是将字符转为字节序列
null 和 undefined 的区别
undefined 是未被设置的值;null 是人为设置的空对象
undefined出现场景:
1. 声明了变量,但是没有赋值;
2. 访问对象上不存在的属性;
3. 函数上未接收到实参的形参;
4. 使用void表达式求职;
数组和伪数组的区别
数组是一个特殊的对象;
当添加新元素时,自动更新length;
设置length可以截断数组;
从Array.prototype中继承了方法;
类数组具有length属性;
为普通对象;
不继承数组的方法;
手写发布订阅
class Observer{
private caches ={}
on(eventName, fn){this.caches[eventName]=this.caches[eventName]|| [] ; this.caches.push(fn)}
emit(eventName, data){ this.caches[this.eventName] && this.caches[eventName].forEach(fn=> fn(data))}
off(eventName, fn){this.caches[eventName] && this.caches[eventName].filter(f => f !== fn)}
}
手写数组转树
function toTree(parenId, array) {
let children = []
let len = array.length
for (let i = 0; i < len; i++) {
let node = array[i]
if (node.parentId === parenId) {
children.push({
id: node.id,
val: node.val,
children: toTree(node.id, array)
})
}
}
return children
}
Set、Map、WeakSet 和 WeakMap 的区别
Set
1. Set 成员不能重复
2. 只有键值,没有键名
3. 可以遍历,方法有add、delete、has
WeakSet
4. 成员都是对象
5. 成员都是弱引用,可以用来报错dom节点,不容易造成内存泄漏
6. 不能遍历,方法有add、delete、has
Map
7. 键值对集合
8. 可以遍历
WeakMap
9. 键名只能是对象
10. 不能遍历
js内存泄漏
1. 意外的全局变量
2. 闭包
3. 未被清空的定时器
4. 未被销毁的事件监听
5. dom引用
promise和 async await 区别
Promise 是异步编程的一种解决方案,Promise好比容器,里面存放着一些未来才会执行完毕(异步)的事件的结果
async await也是异步编程的一种解决方案,他遵循的是Generator 函数的语法糖,他拥有内置执行器,不需要额外的调用直接会自动执行并输出结果,它返回的是一个Promise对象。
区别:
1. Promise解决回调地狱的问题;但是它的回调链同样比较繁琐;
2. async await让异步代码可以同步执行。
3. async await与promise一样,是非阻塞;
4. async await是基于promise实现。
defer和async区别
区别主要在于执行时间,defer在文档解析后执行,多个defer顺序执行;
async在js加载后执行,多个async,哪个加载好执行哪个。
在没有async和defer,立即执行
有async的话,文档加载和渲染会和js的加载和执行异步执行。
有defer的话,文档加载会和js的加载异步执行,js的执行在所有元素解析后执行。
同步和异步
同步:在主线程上的任务,在上一个任务执行完后才会开始下一个任务;
异步:不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务会才会进入主线程;
每一个异步任务都有一个或多个回调函数,前一个任务结束不是执行后一个异步任务,而是执行回调函数;后一个任务则不是等前一个任务结束;
程序的执行顺序和排列顺序不一致;
setTimeout、setInterval等。
实现异步的方法
回调函数、事件监听、发布订阅、promise、generator、async/await
promise的链式调用
1. 每次调用返回的都是一个新的Promise实例
2. 如果then中返回的是一个结果的话会把这个结果传递下一次then中的成功回调
3. 如果then中出现异常,会走下一个then的失败回调
4. 在 then中使用了return,那么 return 的值会被Promise.resolve() 包装
5. then中可以不传递参数
6. catch 会捕获到没有捕获的异常
async/await
async/await 是基于promise实现,不能用于普通回调函数;
函数加上async ,返回promise实例
事件循环
1. 所有任务都在主线程上执行,形成一个执行栈;
2. 主线程之外还存在任务队列,系统把异步任务放在任务队列,然后主线程继续执行后续任务;
3. 一旦执行栈中所有任务执行完毕,系统会读取任务队列,这时异步任务已经结束等待状态,就会从任务队列进入执行栈,恢复执行;
宏任务:
在每个阶段执行的任务
setTimeout、setInterval、setImmediate、I/O、UI render
微任务:
在每个阶段之间执行的任务
nextTick、promise、
script(主程序代码)—>process.nextTick—>Promises...——>setTimeout——>setInterval——>setImmediate——> I/O——>UI rendering
this
call、apply、bind的区别
都可以改变函数内部this的执行。
1. call和apply会调用函数,改变this的执行
2. call传递参数a1,a2...,apply传递参数[a1,a2,...]
3. bind不会调用函数,可以改变函数内部this指向。
函数中this的指向
1. 默认指向调用函数的对象。
2. 匿名函数中this指向window。
3. 箭头函数的this在函数定义时确定,离箭头函数最近的上下文的this就是箭头函数中的this
箭头函数能否当构造函数
不行,箭头函数没有自己的this、arguments、super,只适用于匿名函数。
继承优缺点
优点:
1. 提高了代码的复用性;
2. 提高了代码的维护性;
3. 让类与类建立联系;
缺点:
类的耦合增强,但开发的原则:高内聚,低耦合。
js继承
1. 原型链继承
将子类的原型链指向父类的对象实例。
Child.prototype = new Parent();
优点:可以继承构造函数的属性,父类原型的属性;但无法向父类传参,且所有实例共享父类实例的属性,会影响使用。
2. 构造函数继承
在子类构造函数中使用call或apply劫持父类构造函数,并传入参数,完成父类函数的执行(初始化)
优点:可以解决原型链继承的缺点;但是无法继承父类的原型
3. 组合继承
综合使用原型链继承和构造函数继承。
function Child(name, id){
Parent.call(this, name, id);
// Parent.apply(this, arguments);
}
Child.prototype = new Parent();
var child = new Child("jin", "1");
4. 原型式继承
类似Object.create(),创建一个函数,然后将函数的原型指向目标对象,返回这个函数的实例,就可以了
var parent = {
names: ['a']
}
function copy(object) {
function F() {}
F.prototype = object;
return new F();
}
var child = copy(parent);
5. 寄生式继承
二次封装原型式继承,并拓展。优点是可以添加新的属性和方法。
function createObject(obj) {
var o = copy(obj);
o.getNames = function() {
console.log(this.names);
return this.names;
}
return o;
}
new原理
1. 创建一个空对象
var obj ={}
2. 设置新对象的proto为构造函数的prototype
obj.__proto__ = ClassA.prototype
3. 执行函数并修改this指向obj
ClassA.call(obj)
4. 返回obj。
link和@import区别
使用link:<link href="index.css" rel="stylesheet">
使用@import:
<style type="text/css">
@import url(index.css);
</style>
区别:
link可以引用样式、图片等资源文件;@import只能引用样式
link引入css在页面加载时同时加载;@import需要等页面完全加载后加载
link无兼容问题;@import是css2.1开始的
link支持js控制dom修改样式;@import不支持
为什么link使用href获取资源,script和img使用src
src用于替换当前元素,href用于在当前文档和资源之间确立联系。
src指向外部资源,将指向的内容嵌入到文档当前位置;当浏览器解析该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕。
href指向外部资源,将资源与当前文档建立联系;浏览器识别到link的css文件,会并行下载资源,不会暂停对当前文档的处理。
es6中的箭头函数
箭头函数省略的function关键字,采用箭头来定义函数。
箭头前是参数,后是函数体。
箭头函数如果没有参数,可以用空括号。
箭头函数如果有一个参数,可以省略括号。
箭头函数如果有多个参数,可以用逗号隔开,用括号包起来。
箭头函数如果函数体只有一行代码,并只是想返回某个值可以省略大括号。
箭头函数如果想返回一个对象,可以用括号包起来。
箭头函数中的this指向全局作用域
call/apply/bind无法改变箭头函数this的指向
箭头函数无法作为构造函数使用
箭头函数没有自己的arguments
箭头函数没有prototype
es6新特性
1. 变量和作用域
let、const声明的变量只能在块内使用
let、const声明的变量没有变量提升
const声明时必须赋值
const声明的变量内存地址不可变,const声明的对象,对象内容可变
解构赋值
2. 方法扩展
Object.assign()赋值对象
3. 数据结构Set和Map
Set数组成员不重复,可以用于去重;通过new实例化,入参可以是数组或类数组。
Set的方法:add/delete/has/clear
遍历方法:keys/values/entries/forEach/扩展运算符/map/filter
WeakSet成员只能是对象,对象都是弱引用,如果没有其他对象引用该对象,垃圾回收机制会自动回收。
Object的键只能是字符串和Symbol,Map的key可以取任何类型
Map的方法:set/get/has/delete/clear
遍历方法:同Set
4. Proxy和Reflect
Proxy 拦截对目标对象的访问
Reflect 用于操作对象提供的新API
5. 异步编程
异步编程方案:1.回调函数;2.事件触发监听;3.发布订阅;4.promise
promise有三个状态:pending/fulfilled/rejected
状态的改变只能是pending->fulfilled或者pending->rejected
generator通过*和yield实现;通过next触发执行
async是generator的语法糖,自带执行器,返回promise。
6. class
class的实现也是基于原型,类中所有方法都是定义在prototype上,不可枚举;
通过new实例化,一个类必须有一个constructor方法,默认有一个空的constructor;
如果在类的一个方法前加static,表示该方法不会被实例继承。
7. module
CommonJS用于服务器;AMD用于浏览器。都是在运行时确定模块的依赖关系。
es6的模块是编译时确定
export/import:输入的变量只读、通过export default 指定默认导出。
8. ES6与es5继承的区别
es6继承是通过class的extends实现;es5的继承是通过prototype实现。
es6在constructor中通过super实现可以继承原生构造函数的内部属性;es5做不到。
super和A.call(this)区别
es6的super是通过先创建父类实例this,然后用子类构造函数修饰this,使得父类所有行为可以继承;
es5的A.call(this)是先创建子类实例this,然后执行父类函数,继承父类实例属性。
9. 扩展运算符
add(...[4, 38]);
arr1.push(...arr2);
const a2 = [...a1];
const [first, ...rest] = [1, 2, 3, 4, 5];
为什么js是单线程
js作为浏览器的脚本语言,主要实现用户与浏览器的交互以及操作dom;这决定了它只能是单线程,否则会有很复杂的同步问题。