在这里插入图片描述

什么是事件监听

addEventListener()方法,用于向指定元素添加事件句柄,它可以更简单的控制事件。语
法为:

element.addEventListener(event, function, useCapture);
  1. 第一个参数是事件的类型(如 “click” 或 “mousedown”)。
  2. 第二个参数是事件触发后调用的函数
  3. 第三个参数是布尔值,用于描述事件是冒泡还是捕获。(该参数是可选的。)

事件传递有两种方式:冒泡捕获
事件传递定义了元素事件触发的顺序,如果你将 P 元素插入到 div 元素中,用户点击 P元素,在冒泡中,内部元素先被触发,然后再触发外部元素,在捕获中,外部元素先被触发,再触发内部元素。

事件委托以及冒泡原理

  • 事件委托是利用冒泡阶段的运行机制来实现的,就是把一个元素响应事件的函数委托到另一个元素,一般是把一组元素的事件委托到他的父元素上,委托的优点是减少内存消耗,节约效率,动态绑定事件
  • 事件冒泡就是元素自身的事件被触发后,如果父元素有相同的事件,如 onClick 事件,那么元素本身的触发状态就会传递,也就是冒到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到 document/window,冒泡过程结束。

介绍一下 promise,及其底层如何实现

Promise 是一个对象,保存着未来将要结束的事件,有两个特征:

  1. 对象的状态不受外部影响,Promise 对象代表一个异步操作,有三种状态,pending:进行中,fulfilled:已成功,rejected:已失败,只有异步操作的结果,才可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也就是 promise 名字的由来。
  2. 一旦状态改变,就不会再变,promise 对象状态改变只有两种可能:从 pending 到fulfilled 或者从 pending 到 rejected,只要这两种情况发生,状态就凝固了,不会再改变,这个时候就称为定型 resolved。

Promise 的基本用法

let promise1 = new Promise(function(resolve,reject){
	setTimeout(function(){
		resolve('ok')
	},1000)
})
promise1.then(function success(val){
	console.log(val)
})

深浅拷贝的区别

浅拷贝

只是复制指向某个对象的指针,而不是复制对象的本身,新旧对象还是共享同一块内存,修改新对象会改变原对象。(拷贝指向对象的指针)
如果是数组,我们可以利用数组的一些方法,比如 slice,concat 方法返回一个新数组的特性来实现拷贝,但假如数组嵌套了对象或者数组的话,使用 concat 方法克隆并不完整,如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化,我们把这种复制引用的拷贝方法称为浅拷贝

深拷贝

会创造另外一个一模一样的对象,即使嵌套了对象,两者也互相分离(把这个对象原封不动地再copy出新的一份,和原对象互不相干),新对象和原对象不共享同一块内存,修改新对象不会修改原对象。(拷贝对象)

如何深拷贝一个数组
这里介绍一个技巧,不仅适用于数组还适用于对象!

var arr = ['old', 1, true, ['old1', 'old2'], { old: 1 }]
console.log(JSON.stringify(arr))   //["old",1,true,["old1","old2"],{"old":1}]
var new_arr = JSON.parse(JSON.stringify(arr));
console.log(new_arr); //['old', 1, true, ['old1', 'old2'], { old: 1 }]

原理是 JOSN 对象中的 stringify 可以把一个 js 对象序列化为一个 JSON 字符串parse 可以把 JSON 字符串反序列化为一个 js 对象,通过这两个方法,也可以实现对象的深复制。但是这个方法不能够拷贝函数。

let、const、var的区别

  1. var 声明的变量是全局或者整个函数块的,而 let,const 声明的变量是块级的变量
  2. var 声明的变量存在变量提升,let,const 不存在。
  3. let 声明的变量允许重新赋值,const 不允许。

ES6 箭头函数的特性

ES6 增加了箭头函数,基本语法为:

let func = value => value;
相当于
let func = function (value) {
return value;
};

箭头函数与普通函数的区别在于:

  1. 箭头函数没有 this,所以需要通过查找作用域链来确定 this 的值,这就意味着如果箭头函数被非箭头函数包含,this 绑定的就是最近一层非箭头函数的 this。
  2. 箭头函数没有自己的 arguments 类数组 对象,但是可以访问外围函数的 arguments 对象。
  3. 不能通过 new 关键字调用,同样也没有 new.target 值和原型。

setTimeout 和 Promise 的执行顺序

首先我们来看这样一道题:

setTimeout(function () {
      console.log(1)
    }, 0);
    new Promise(function (resolve, reject) {
      console.log(2)
      for (var i = 0; i < 10000; i++) {
        if (i === 10) { console.log(10) }
        i == 9999 && resolve();
      }
      console.log(3)
    }).then(function () {
      console.log(4)
    })
    console.log(5);

 //打印结果:2 10 3 5 4 1

要先弄清楚 setTimeout(function,0)何时执行,Promise 何时执行,then 何时执行。

  • setTimeout 这种异步操作的回调,只有主线程中没有执行任何同步代码的前提下,才会执行异步回调,而setTimeout(fun,0)表示立刻执行,也就是用来改变任务的执行顺序要求浏览器尽可能快的进行回调
  • Promise 何时执行:Promise 新建后立即执行,所以 Promise 构造函数里代码同步执行的。
  • then 方法指向的回调将在当前脚本所有同步任务执行完成后执行
    那么 then 为什么比 settimeout 执行的早呢?
    因为 settimeout(fun,0)不是真的立即执行,经过测试得出结论:执行顺序为:同步执行的代码 => Promise.then => setTimeout