javaScript总结(10-15)

本文详细解读了JavaScript中的this关键字的动态绑定、执行上下文(包括全局、函数和eval上下文)的作用和生命周期,以及事件模型(原始、标准和IE模型)的区别。此外,介绍了typeof和instanceof在判断数据类型上的异同及其应用场景。
摘要由CSDN通过智能技术生成

十一、说说你对Javascript中this对象的理解

this关键字在javascript严格模式和非严格模式下有一些差别
大多数情况下,函数的调用方式决定了this的值(运行时绑定)
this 关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象
同时,this在函数执行过程中,this一旦被确定了,就不可以再更改

默认绑定:在全局定义的函数中,浏览器环境:this默认指向window,node环境:this默认指向global,严格模式下:this默认指向undefined
隐式绑定:在对象中方法的this,this指向上一级对象
new绑定:this指向这个实例对象
显示修改:apply(),call(),bind()对this进行修改

new绑定优先级 > 显示绑定优先级 > 隐式绑定优先级 > 默认绑定优先级
箭头函数
在 ES6 的语法中还提供了箭头函语法,让我们在代码书写时就能确定 this 的指向(编译时绑定)

小结:this是在函数运行时自动创建的一个内部对象,只能在函数内部使用,在函数运行时一旦确定,就不能在更改。
this默认绑定在不同环境,不同严格模式下的指向都不同,在浏览器默认指向window,node默认指向global,严格模式下默认绑定nudefined
在对象中的方法会隐式绑定为上以及对象
使用new关键字时会绑定为实例对象
当然我们也可以通过call,apply,bind对this的指向进行修改。
es6中的箭头函数中的this在书写就会确定,编译时会绑定。

十二、JavaScript中执行上下文和执行栈是什么?

1.执行上下文
简单的来说,执行上下文是对Javascript代码执行环境的一种抽象概念,只要有Javascript代码运行,那么它就一定是运行在执行上下文中

执行上下文的类型分为三种:

全局执行上下文:只有一个,浏览器中的全局对象就是 window对象,this 指向这个全局对象
函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
Eval 函数执行上下文:指的是运行在 eval 函数中的代码,很少用而且不建议使用
生命周期:
执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段

创建阶段
创建阶段即当函数被调用,但未执行任何其内部代码之前

创建阶段做了三件事:

  • 确定 this 的值,也被称为 This Binding
  • LexicalEnvironment(词法环境) 组件被创建
  • VariableEnvironment(变量环境) 组件被创建
    执行阶段
    在这阶段,执行变量赋值、代码执行

如果 Javascript 引擎在源代码中声明的实际位置找不到变量的值,那么将为其分配 undefined 值
回收阶段
执行上下文出栈等待虚拟机回收执行上下文

2.执行栈
执行栈,也叫调用栈,具有 LIFO(后进先出)结构,用于存储在代码执行期间创建的所有执行上下文

当Javascript引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中

每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中

引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文

小结:执行上下文时javascript代码运行的抽象概念,只要代码在运行,那他一定在执行上下文的过程中,一般分为全局执行上下文、函数执行上下文、eval函数执行上下文,生命周期一般包括创建阶段-执行阶段-回收阶段。创建阶段会确定this指向,执行阶段会进行变量赋值、代码运行等操作,回收阶段就会等待回收执行上下文。
执行栈就是在创建执行上下文时会压入执行栈中,先压入全局执行上下文,调用函数就会压入该函数执行上下文,以此类推,因为执行栈拥有后进先出的结构,所以当全局执行上下文被压出栈时,程序结束。

十三、JavaScript中的事件模型如何理解?

1.事件与事件流
javascript中的事件,可以理解就是在HTML文档或者浏览器中发生的一种交互操作,使得网页具备互动性, 常见的有加载事件、鼠标事件、自定义事件等

由于DOM是一个树结构,如果在父子节点绑定事件时候,当触发子节点的时候,就存在一个顺序问题,这就涉及到了事件流的概念

事件流都会经历三个阶段:

事件捕获阶段(capture phase)
处于目标阶段(target phase)
事件冒泡阶段(bubbling phase)
2.事件模型可以分为三种:

原始事件模型(DOM0级)
特性 绑定速度快
DOM0级事件具有很好的跨浏览器优势,会以最快的速度绑定,但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行
只支持冒泡,不支持捕获
同一个类型的事件只能绑定一次

var btn = document.getElementById('.btn');
btn.onclick = fun;

标准事件模型(DOM2级)
在该事件模型中,一次事件共有三个过程:
事件捕获阶段:事件从document一直向下传播到目标元素, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行
事件处理阶段:事件到达目标元素, 触发目标元素的监听函数
事件冒泡阶段:事件从目标元素冒泡到document,依次检查经过的节点是否绑定了事件监听函数

addEventListener(eventType, handler, useCapture)

IE事件模型(基本不用)

IE事件模型共有两个过程:

事件处理阶段:事件到达目标元素, 触发目标元素的监听函数。 事件冒泡阶段:事件从目标元素冒泡到document,
依次检查经过的节点是否绑定了事件监听函数,如果有则执行

var btn = document.getElementById('.btn');
btn.attachEvent(‘onclick’, showMessage);
btn.detachEvent(‘onclick’, showMessage);

小结:说到事件模型就得先知道事件和事件流,js中的事件就是点击事件、加载事件等,因为dom是个树形结构,所以在处理事件时就会出现一个顺序问题,这就引出了事件流,它包括事件捕获阶段、事件处理阶段、事件冒泡阶段。
而js的事件模型包括
原始事件模型,属于dom0级事件,onclick\onblur等,直接绑定,特点就是绑定快
标准事件模型,属于dom2级事件,addeventlistener,从document先捕获以此检查是否绑定监听函数,如果有则执行,再处理事件触发目标元素的监听函数,再冒泡至document依此检查是否有事件监听函数,如果有则执行。
特点是可以绑定多个事件处理器,互不冲突。
ie事件模型,事件到达目标函数执行监听函数,再冒泡到document,依次检查经过节点是否绑定事件监听,如果有则执行

十四、说说 typeof 与 instanceof 区别?

1.typeof
typeof 操作符返回一个字符串,表示未经计算的操作数的类型

typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof null // 'object'
typeof [] // 'object'
typeof {} // 'object'
typeof console // 'object'
typeof console.log // 'function'

从上面例子,前6个都是基础数据类型。虽然typeof null为object,但这只是JavaScript 存在的一个悠久 Bug,不代表null就是引用数据类型,并且null本身也不是对象
(这跟javascript的存储方式有关,在Javascript在存储的时候,会将不同的对象在底层存储都使用二进制的方式存储,在Javascript中如果二进制的前三位都为0的话就会被判断为object,null的二进制存储表示形式为全是0,自然前三位也是0,因此执行typeof时会返回”object”。)

所以,null在 typeof之后返回的是有问题的结果,不能作为判断null的方法。如果你需要在 if 语句中判断是否为 null,直接通过===null来判断就好

同时,可以发现引用类型数据,用typeof来判断的话,除了function会被识别出来之外,其余的都输出object

如果我们想要判断一个变量是否存在,可以使用typeof:(不能使用if(a), 若a未声明,则报错)

2.instanceof
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
构造函数通过new可以实例对象,instanceof能判断这个对象是否是之前那个构造函数生成的对象

// 定义构建函数
let Car = function() {}
let benz = new Car()
benz instanceof Car // true
let car = new String('xxx')
car instanceof String // true
let str = 'xxx'
str instanceof String // false

关于instanceof的实现原理,可以参考下面:

function myInstanceof(left, right) {
    // 这里先用typeof来判断基础数据类型,如果是,直接返回false
    if(typeof left !== 'object' || left === null) return false;
    // getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
    let proto = Object.getPrototypeOf(left);
    while(true) {                  
        if(proto === null) return false;
        if(proto === right.prototype) return true;//找到相同原型对象,返回true
        proto = Object.getPrototypeof(proto);
    }
}

也就是顺着原型链去找,直到找到相同的原型对象,返回true,否则为false
3.区别

typeof与instanceof都是判断数据类型的方法,区别如下:

  • typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值
  • instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型
  • 而typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function
    类型以外,其他的也无法判断
    解决办法
    如果需要通用检测数据类型,可以采用Object.prototype.toString,调用该方法,统一返回格式“[object Xxx]”的字符串
Object.prototype.toString({})       // "[object Object]"
Object.prototype.toString.call({})  // 同上结果,加上call也ok
Object.prototype.toString.call(1)    // "[object Number]"
Object.prototype.toString.call('1')  // "[object String]"
Object.prototype.toString.call(true)  // "[object Boolean]"
Object.prototype.toString.call(function(){})  // "[object Function]"
Object.prototype.toString.call(null)   //"[object Null]"
Object.prototype.toString.call(undefined) //"[object Undefined]"
Object.prototype.toString.call(/123/g)    //"[object RegExp]"
Object.prototype.toString.call(new Date()) //"[object Date]"
Object.prototype.toString.call([])       //"[object Array]"
Object.prototype.toString.call(document)  //"[object HTMLDocument]"
Object.prototype.toString.call(window)   //"[object Window]"

小结:typeof是用来检测数据类型的·,返回值是监测数据的类型,其中在检测null的类型时会返回Object,而null本质是基本数据类型,这是因为javascript在存储数据时是使用二进制存储,在判定是否为Object时是查看前三位是否是0,而null存储的全是0,所以null被判定为Object,
instanceof是用来检测构造函数的prototype的某个属性是否在某个实例的原型链上,函数左侧时实例对象,右侧是目标属性,返回值时true或false,通过new关键字创建的实例可以通过instanceof判断该实例是否是某构造函数创造的。
相同点:都是判断数据类型的方法
不同的:typeof返回的是数据类型,instanceof返回的是布尔值。
instanceof可以准确判断数据类型但是不能正确判断基础数据类型,而typeof在判断null是会返回Object,并且复杂类型只有function会返回function,其他都会返回Object。
解决方法:使用Object.prototype.toString,调用该方法会返回[Object Xxx]格式的字符串。

十五、解释下什么是事件代理?应用场景?

事件代理,俗地来讲,就是把一个元素响应事件(click、keydown…)的函数委托到另一个元素

前面讲到,事件流的都会经过三个阶段:捕获阶段 -> 目标阶段 -> 冒泡阶段,而事件委托就是在冒泡阶段完成

事件委托,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素

当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数

应用场景:
如果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件
如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的
这时候就可以事件委托,把点击事件绑定在父级元素ul上面,然后执行事件的时候再去匹配目标元素

小结:事件代理通俗来讲就是将一个元素的事件函数绑定或委托到另一个元素上,因为事件流包括捕获-目标-冒泡三个阶段,我们将同一类的处理函数绑定到他们的父层或更高层元素上,当事件响应到目标函数时会通过冒泡机制触发到外层绑定的事件上。应用场景一般在列表标签上ul-li,可以将li的点击事件委托给ul,具体例子有导航栏。

注意:学习总结
参考链接:https://github.com/febobo/web-interview

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值