【知识总结】JavaScript核心问题汇总

JavaScript有哪些数据类型,区别是什么?

undefined、null、boolean、number、string、object、symbol、bigint

其中 Symbol 和 BigInt 是ES6 中新增的数据类型:

  • Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
  • BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。

这些数据可以分为原始数据类型引用数据类型

  • 栈:原始数据类型(Undefined、Null、Boolean、Number、String)
  • 堆:引用数据类型(对象、数组和函数)

数据类型检测方式有哪些?

1)typeof

其中数组、对象、null都会被判断为object,其他判断都正确。

2)instanceof

instanceof可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。

console.log(2 instanceof Number);                    // false
console.log(true instanceof Boolean);                // false 
console.log('str' instanceof String);                // false 
 
console.log([] instanceof Array);                    // true
console.log(function(){
    
    } instanceof Function);       // true
console.log({
    
    } instanceof Object);                   // true

可以看到,instanceof只能正确判断引用数据类型,而不能判断基本数据类型。instanceof 运算符可以用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

3)constructor

  • 判断数据的类型
  • 对象实例通过 constrcutor 对象访问它的构造函数

4)Object.prototype.toString.call()

Object.prototype.toString.call() 使用 Object 对象的原型方法 toString 来判断数据类型。

同样是检测对象obj调用toString方法,obj.toString()的结果和Object.prototype.toString.call(obj)的结果不一样,这是为什么?

这是因为toString是Object的原型方法,而Array、function等类型作为Object的实例,都重写了toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法(function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object原型上的toString方法。

判断数组的方式有哪些?

1)Object.prototype.toString.call()

Object.prototype.toString.call(obj).slice(8,-1) === 'Array';

2)原型链

obj.__proto__ === Array.prototype;

3)Array.isArray()

Array.isArrray(obj);

4)instanceof

obj instanceof Array

5)Array.prototype.isPrototypeOf

Array.prototype.isPrototypeOf(obj)

null和undefined区别是什么?

首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。

undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。

undefined 在 JavaScript 中不是一个保留字,这意味着可以使用 undefined 来作为一个变量名,但是这样的做法是非常危险的,它会影响对 undefined 值的判断。我们可以通过一些方法获得安全的 undefined 值,比如说 void 0。

当对这两种类型使用 typeof 进行判断时,Null 类型化会返回 “object”,这是一个历史遗留的问题。当使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。

typeof null 的结果是什么,为什么?

typeof null 的结果是Object。

在 JavaScript 第一个版本中,所有值都存储在 32 位的单元中,每个单元包含一个小的 类型标签(1-3 bits) 以及当前要存储值的真实数据。类型标签存储在每个单元的低位中,共有五种数据类型:

000: object   - 当前存储的数据指向一个对象。
  1: int      - 当前存储的数据是一个 31 位的有符号整数。
010: double   - 当前存储的数据指向一个双精度的浮点数。
100: string   - 当前存储的数据指向一个字符串。
110: boolean  - 当前存储的数据是布尔值。

如果最低位是 1,则类型标签标志位的长度只有一位;如果最低位是 0,则类型标签标志位的长度占三位,为存储其他四种数据类型提供了额外两个 bit 的长度。

有两种特殊数据类型:

  • undefined的值是 (-2)30(一个超出整数范围的数字);
  • null 的值是机器码 NULL 指针(null 指针的值全是 0)

那也就是说null的类型标签也是000,和Object的类型标签一样,所以会被判定为Object。

intanceof 操作符的实现原理及实现?

instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。

function myInstanceof(left,right){
    
    
	let proto = Object.getPrototypeOf(left) // 获取对象的原型
	let prototype = right.prototype;  获取构造函数的 prototype 对象
	while(true){
    
     // 判断构造函数的 prototype 对象是否在对象的原型链上
		if(!proto) return false;
		if(proto === prototype) return true;
		proto = Object.getPrototypeOf(proto);  // 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型
	}
}
``

## 为什么0.1+0.2 ! == 0.3,如何让其相等?
 

```javascript
(n1 + n2).toFixed(2) // toFixed(num) 方法可把 Number 四舍五入为指定小数位数的数字。

计算机是通过二进制的方式存储数据的,所以计算机计算0.1+0.2的时候,实际上是计算的两个数的二进制的和。0.1的二进制是0.0001100110011001100…(1100循环),0.2的二进制是:0.00110011001100…(1100循环),这两个数的二进制都是无限循环的数。那JavaScript是如何处理无限循环的二进制小数呢?

一般我们认为数字包括整数和小数,但是在 JavaScript 中只有一种数字类型:Number,它的实现遵循IEEE 754标准,使用64位固定长度来表示,也就是标准的double双精度浮点数。在二进制科学表示法中,双精度浮点数的小数部分最多只能保留52位,再加上前面的1,其实就是保留53位有效数字,剩余的需要舍去,遵从“0舍1入”的原则。

如何实现0.1+0.2=0.3呢?只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3

function numberepsilon(arg1,arg2){
    
                       
  return Math.abs(arg1 - arg2) < Number.EPSILON;        
}        
console.log(numberepsilon(0.1 + 0.2, 0.3)); // true

如何获取安全的undefind值?

因为 undefined 是一个标识符,所以可以被当作变量来使用和赋值,但是这样会影响 undefined 的正常判断。表达式 void ___ 没有返回值,因此返回结果是 undefined。void 并不改变表达式的结果,只是让表达式不返回值。因此可以用 void 0 来获得 undefined。

typeof NaN 的结果是什么?

NaN 指“不是一个数字”(not a number),NaN 是一个“警戒值”(sentinel value,有特殊用途的常规值),用于指出数字类型中的错误情况,即“执行数学运算没有成功,这是失败后返回的结果”。

typeof NaN; // "number"

NaN 是一个特殊值,它和自身不相等,是唯一一个非自反(自反,reflexive,即 x === x 不成立)的值。而 NaN !== NaN 为 true。

isNaN 和 Number.isNaN 函数的区别?

  • 函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。
  • 函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

== 操作符的强制类型转换规则?

对于 == 来说,如果对比双方的类型不一样,就会进行类型转换。假如对比 x 和 y 是否相同,就会进行如下判断流程:

  1. 首先会判断两者类型是否相同,相同的话就比较两者的大小;
  2. 类型不相同的话,就会进行类型转换;
  3. 会先判断是否在对比 null 和 undefined,是的话就会返回 true
  4. 判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number
  5. 判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断
  6. 判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断

其他值到字符串的转换规则?

  • Null 和 Undefined 类型 ,null 转换为 “null”,undefined 转换为 “undefined”
  • Boolean 类型,true 转换为 “true”,false 转换为 “false”。
  • Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。
  • Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。
  • 对普通对象来说,除非自行定义 toString() 方法,否则会调用 toString()(Object.prototype.toString())来返回内部属性 [[Class]] 的值,如"[object Object]"。如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。

其他值到数字值的转换规则?

  • Undefined 类型的值转换为 NaN。
  • Null 类型的值转换为 0。
  • Boolean 类型的值,true 转换为 1,false 转换为 0。
  • String 类型的值转换如同使用 Number() 函数进行转换,如果包含非数字值则转换为 NaN,空字符串为 0。
  • Symbol 类型的值不能转换为数字,会报错。
  • 对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。

Object.is() 与比较操作符 “ === ” 和 “ == ” 的区别?

  • 使用双等号(==)进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。
  • 使用三等号(===)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。
  • 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。

object.assign和扩展运算法是深拷贝还是浅拷贝,两者区别

扩展运算符:

let outObj = {
    
    
  inObj: {
    
    a: 1, b: 2}
}
let newObj = {
    
    ...outObj}
newObj.inObj.a = 2
console.log(outObj) // {inObj: {a: 2, b: 2}}

Object.assign():

let outObj = {
    
    
  inObj: {
    
    a: 1, b: 2}
}
let newObj = Object.assign({
    
    }, outObj)
newObj.inObj.a = 2
console.log(outObj) // {inObj: {a: 2, b: 2}}

let、const、var区别

1)块级作用域:块作用域由 { }包括,let和const具有块级作用域,var不存在块级作用域。块级作用域解决了ES5中的两个问题:

  1. 内层变量可能覆盖外层变量
  2. 用来计数的循环变量泄露为全局变量

2)变量提升:var存在变量提升,let和const不存在变量提升,即在变量只能在声明之后使用,否在会报错。

3)给全局添加属性:浏览器的全局对象是window,Node的全局对象是global。var声明的变量为全局变量,并且会将该变量添加为全局对象的属性,但是let和const不会。

4)重复声明:var声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的遍历。const和let不允许重复声明变量。
5)暂时性死区:在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。使用var声明的变量不存在暂时性死区。
6)初始值设置:在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。
7)指针指向:let和const都是ES6新增的用于创建变量的语法。 let创建的变量是可以更改指针指向(可以重新赋值)。但const声明的变量是不允许改变指针的指向。
在这里插入图片描述

const对象的属性可以修改吗?

const保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。对于基本类型的数据(数值、字符串、布尔值),其值就保存在变量指向的那个内存地址,因此等同于常量。

但对于引用类型的数据(主要是对象和数组)来说,变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针是固定不变的,至于它指向的数据结构是不是可变的,就完全不能控制了。

如果new一个箭头函数的会怎么样?

箭头函数是ES6中的提出来的,它没有prototype,也没有自己的this指向,更不可以使用arguments参数,所以不能New一个箭头函数。

new操作符的实现步骤如下:

  • 创建一个对象
  • 将构造函数的作用域赋给新对象(也就是将对象的__proto__属性指向构造函数的prototype属性)
  • 指向构造函数中的代码,构造函数中的this指向该对象(也就是为这个对象添加属性和方法)
  • 返回新的对象
    所以,上面的第二、三步,箭头函数都是没有办法执行的。

箭头函数与普通函数的区别

1)箭头函数比普通函数更加简洁

  • 如果没有参数,就直接写一个空括号即可
  • 如果只有一个参数,可以省去参数的括号
  • 如果有多个参数,用逗号分割
  • 如果函数体的返回值只有一句,可以省略大括号
  • 如果函数体不需要返回值,且只有一句话,可以给这个语句前面加一个void关键字。最常见的就是调用一个函数:
let fn = () => void doesNotReturn();

2)箭头函数没有自己的this

箭头函数不会创建自己的this, 所以它没有自己的this,它只会在自己作用域的上一层继承this。所以箭头函数中this的指向在它在定义时已经确定了,之后不会改变。

3)箭头函数继承来的this指向永远不会改变

var id = 'GLOBAL';
var obj = {
    
    
  id: 'OBJ',
  a: function(){
    
    
    console.log(this.id);
  },
  b: () => {
    
    
    console.log(this.id);
  }
};
obj.a();    // 'OBJ'
obj.b();    // 'GLOBAL'
new obj.a()  // undefined
new obj.b()  // Uncaught TypeError: obj.b is not a constructor

对象obj的方法b是使用箭头函数定义的,这个函数中的this就永远指向它定义时所处的全局执行环境中的this,即便这个函数是作为对象obj的方法调用,this依旧指向Window对象。需要注意,定义对象的大括号{}是无法形成一个单独的执行环境的,它依旧是处于全局执行环境中。

箭头函数的this指向哪⾥?

箭头函数不同于传统JavaScript中的函数,箭头函数并没有属于⾃⼰的this,它所谓的this是捕获其所在上下⽂的 this 值,作为⾃⼰的 this 值,并且由于没有属于⾃⼰的this,所以是不会被new调⽤的,这个所谓的this也不会被改变。

说一下闭包

一句话可以概括:闭包就是能够读取其他函数内部变量的函数,或者子函数在外调用,子函数所在的父函数的作用域不会被释放。

继承

原型链继承

  • 特点:基于原型链,既是父类的实例,也是子类的实例
  • 缺点:无法实现多继承

构造继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

  • 特点:可以实现多继承
  • 缺点:只能继承父类实例的属性和方法,不能继承原型上的属性和方法。

实例继承:为父类实例添加新特性,作为子类实例返回

拷贝继承:拷贝父类元素上的属性和方法

组合继承:相当于构造继承和原型链继承的组合体。通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

  • 特点:可以继承实例属性/方法,也可以继承原型属性/方法
  • 缺点:调用了两次父类构造函数,生成了两份实例

寄生组合继承:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性。

如何解决异步回调地狱

promise、generator、async/await

如何让事件先冒泡后捕获

在DOM标准事件模型中,是先捕获后冒泡。但是如果要实现先冒泡后捕获的效果,对于同一个事件,监听捕获和冒泡,分别对应相应的处理函数,监听到捕获事件,先暂缓执行,直到冒泡事件被捕获后再执行捕获之间。

说一下事件委托

事件委托指的是,不在事件的发生地(直接dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素DOM的类型,来做出不同的响应。

好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发机制。

说一下图片的懒加载和预加载

预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。

懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。

mouseover和mouseenter的区别

mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout

mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave

js的new操作符做了哪些事情

new 操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。

改变函数内部this指针的指向函数(bind,apply,call的区别)

通过apply和call改变函数的this指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply是数组,而call则是arg1,arg2…这种形式。通过bind改变this作用域会返回一个新的函数,这个函数不会马上执行。

异步加载js的方法

defer:只支持IE如果您的脚本不会改变文档的内容,可将 defer 属性加入到script标签中,以便加快处理文档的速度。因为浏览器知道它将能够安全地读取文档的剩余部分而不用执行脚本,它将推迟对脚本的解释,直到文档已经显示给用户为止。

async,HTML5属性仅适用于外部脚本,并且如果在IE中,同时存在defer和async,那么defer的优先级比较高,脚本将在页面完成时执行。

JS中的垃圾回收机制

由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。

eval是做什么的

它的功能是将对应的字符串解析成js并执行,应该避免使用js,因为非常消耗性能(2次,一次解析成js,一次执行)

如何理解前端模块化

前端模块化就是复杂的文件编程一个一个独立的模块,比如js文件等等,分成独立的模块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题,所以有了commonJS规范,AMD,CMD规范等等,以及用于js打包(编译等处理)的工具webpack。

说一下Commonjs、AMD和CMD

一个模块是能实现特定功能的文件,有了模块就可以方便的使用别人的代码,想要什么功能就能加载什么模块。

Commonjs:开始于服务器端的模块化,同步定义的模块化,每个模块都是一个单独的作用域,模块输出,modules.exports,模块加载require()引入模块。

AMD:中文名异步模块定义的意思。

js判断类型

判断方法:typeof(),instanceof,Object.prototype.toString.call()等

数组常用方法

push(),pop(),shift(),unshift(),splice(),sort(),reverse(),map()等

数组去重

  • indexOf循环去重
  • ES6 Set去重;Array.from(new Set(array))
  • Object 键值对去重;把数组的值存成 Object 的 key 值,比如 Object[value1] =
    true,在判断另一个值的时候,如果 Object[value2]存在的话,就说明该值是重复的。

性能优化

减少HTTP请求、使用内容发布网络(CDN)、添加本地缓存、压缩资源文件、避免使用CSS表达式、减少DNS查询、使用外部javascript和CSS、避免重定向、图片懒加载

Js基本数据类型

undefined、null、number、boolean、string、symbol

跨域的原理

跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制,那么只要协议、域名、端口有任何一个不同,都被当作是不同的域。跨域原理,即是通过各种方式,避开浏览器的安全限制。

webpack用来干什么的

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle。

简单介绍一下symbol

Symbol是ES6 的新增属性,代表用给定名称作为唯一标识,这种类型的值可以这样创建,let id=symbol(“id”)

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

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

  • 对象的状态不受外部影响,Promise对象代表一个异步操作,有三种状态,pending进行中,fulfilled已成功,rejected已失败,只有异步操作的结果,才可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也就是promise名字的由来。

  • 一旦状态改变,就不会再变,promise对象状态改变只有两种可能,从pending改到fulfilled或者从pending改到rejected,只要这两种情况发生,状态就凝固了,不会再改变,这个时候就称为定型resolved。

js字符串转数字的方法

通过函数parseInt(),可解析一个字符串,并返回一个整数,语法为parseInt(string ,radix)

  • string:被解析的字符串
  • radix:表示要解析的数字的基数,默认是十进制,如果radix<2或>36,则返回NaN

##let const var的区别

提起这三个最明显的区别是var声明的变量是全局或者整个函数块的,而let,const声明的变量是块级的变量,var声明的变量存在变量提升,let,const不存在,let声明的变量允许重新赋值,const不允许。

ES6箭头函数的特性

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

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

简单讲一讲ES6的一些新特性

  • 块级作用域:ES5只有全局作用域和函数作用域,块级作用域的好处是不再需要立即执行的函数表达式,循环体中的闭包不再有问题。
  • rest参数:用于获取函数的多余参数,这样就不需要使用arguments对象了。
  • promise:一种异步编程的解决方案,比传统的解决方案回调函数和事件更合理强大
    模块化:其模块功能主要有两个命令构成,export和import,export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能

call和apply是用来做什么?

Call和apply的作用是一模一样的,只是传参的形式有区别而已

1、改变this的指向

2、借用别的对象的方法,

3、调用函数,因为apply,call方法会使函数立即执行

知道private和public吗

public:public表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用

private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用

js中常见的内存泄漏

  • 意外的全局变量
  • 被遗忘的计时器或回调函数
  • 脱离dom的引用
  • 闭包

什么是事件冒泡

一个事件触发后,会在子元素和父元素之间传播,这种传播分为三个阶段。

  1. 捕获阶段:从window对象传导到目标节点(从外到里),这个阶段不会响应任何事件
  2. 目标阶段:从目标节点上触发
  3. 冒泡阶段:从目标节点传导回window对象(从里到外)。事件委托/事件代理就是利用事件冒泡的机制把里层需要响应的事件绑定到外层。

一个页面输入URL到页面加载显示完成,这个过程都发生了什么

  1. 当发送一个URL请求时,不管这个URL上Web页面的URL还是Web页面上每个资源的URL,浏览器都会开启一个线程来处理这个请求,同时在远程DNS服务器上启动了一个DNS查询。这能使浏览器获取请求对应的ip地址。
  2. 浏览器与远程web服务器通过TCP三次握手协商来建立一个TCP/IP连接。该握手包括一个同步报文、一个同步-应答报文、一个应答报文,这三个报文在浏览器和服务器之间传递。该握手首先由客户端尝试建立起通信,然后服务器响应并接受客户端的请求,最后由客户端发出该请求已经被接受的报文。
  3. 一旦TCP/IP连接建立,浏览器会通过该连接向远处服务器发送HTTP的GET请求。远程服务器找到资源并使用HTTP响应返回该资源。
  4. 此时,web服务器提供资源服务,客户端开始下载资源。

说说前端中的事件流

HTML中与JavaScript交互是通过事件驱动来实现的,例如鼠标点击事件onclick、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是什么时候进行调用的,就需要了解一下“事件流”的概念。

什么是事件流:事件流描述的是从页面中接受事件的顺序,DOM2级事件包括以下几个阶段:事件捕获阶段、目标阶段、事件冒泡阶段

addEventListener:addEventListener是DOM2级事件新增的指定事件处理程序的操作,这个方法接收3个参数(要处理的事件名、作为事件处理程序的函数、一个布尔值)。最后布尔值如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

IE只支持事件冒泡。

猜你喜欢

转载自blog.csdn.net/weixin_42224055/article/details/120346809