最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 前端面试之JavaScript基础(二)—— this

    正文概述 掘金(馒头君)   2021-02-26   399

    this 在实际的开发中经常出现,但是许多人对于 this 的指向常常无法进行准确的判断,今天就带大家了解下 this 的指向问题。

    误解

    this 是什么?this 是一种与函数相关的机制,它被自动的定义在函数的作用域中。我们在使用 this 时常常有两大误解:

    this 指向函数自身

    单从 this 这个单词语义出发,确实容易让开发者误认为 this 指向函数自身,接下来请看一个例子:

    function foo() {
      this.count++
    }
    
    foo.count = 0
    
    for (let i = 0; i < 3; i += 1) {
      foo()
    }
    
    console.log(foo.count)
    

    上述例子中,foo 函数希望用自身的属性 count 记录自己被调用的次数。假设 this 指向函数自身的话,那么最终控制台打印出的结果应该是 3,但是当你实际运行完代码时会发现打印出的结果仍然是 0,这就充分的证明了 this 指向函数自身是 错误 的。

    this 指向函数的词法作用域

    this 指向函数的词法作用域这个观点在某些情况看起来好像成立,但是这样的理解有些偏颇,所以这个观点仍然是错误的。

    绑定机制

    上面说了两点 this 指向的错误理解,那 this 究竟指向什么呢?

    this 实际上是在函数被 调用 时才发生绑定,它指向什么完全取决于函数的调用方式。用函数声明的代码去分析 this 的指向没有意义,接下来我们来看看 this 的绑定规则:

    new 绑定

    在 JavaScript 中也存在 new 操作符,常规是与函数搭配使用,我们先来讲解下当 new 与函数搭配进行函数调用时会发生什么:

    1. 创建一个全新的对象。
    2. 这个新对象的 [[Prototype]] 会与函数的 prototype 进行关联。
    3. 这个新对象会绑定到函数调用的 this 上。
    4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个全新的对象。

    我们重点来关注1、3、4点,请看例子:

    function Person(name) {
      this.name = name
    }
    
    var person = new Person('O_c')
    
    console.log(person.name) // O_c
    

    上述例子中,new 操作符与 Person 函数搭配,在函数调用时会生成一个新的对象 person,并且 person 对象会绑定到函数调用的 this上,所以当执行 this.name = name 时,就是在执行 person.name = name

    现在了解了 new 操作符可以影响函数调用的 this 绑定行为,这称之为 new 绑定。

    显示绑定

    在 JavaScript 中绝大多数的函数都拥有 call(...)apply(...) 这两个方法。它们的第一个参数是一个对象,它们会把这个对象绑定到函数调用的 this 上,这种直接指定 this 指向的操作就称为 显示绑定

    function foo() {
      console.log(this.a)
    }
    
    var obj = {
      a: 2
    }
    
    foo.call(obj) // 2
    

    上述例子中,我们用 call(...) 方法显示的将 obj 对象绑定到 foo 函数调用的 this 上。

    隐式绑定

    当函数 引用 具有上下文对象时,函数调用时的 this 就会绑定到这个上下文对象上,这就是 隐式绑定 规则。

    function foo() {
      console.log(this.a)
    }
    
    var obj = {
      a: 2,
      foo: foo
    }
    
    obj.foo() // 2
    

    上述例子中,foo 被"包含"在上下文对象 obj 中,所以在函数调用时,隐式绑定规则就将 obj 对象绑定在了 foothis 上。

    隐式绑定丢失

    隐式绑定丢失经常发生在 赋值 操作中,在进行赋值操作时因为丢失上下文对象,所以会导致 this 发生非预期的绑定现象,请看以下例子:

    var a = 'global'
    
    function foo() {
      console.log(this.a)
    }
    
    var obj = {
      a: 2,
      foo: foo
    }
    
    var bar = obj.foo
    
    bar(); // global
    

    因为函数是引用类型,当我们将 obj.foo 赋值给 bar 时,实际上 bar 标识符就直接指向了 foo 函数的内存地址。这时我们调用 bar 就等同于直接调用 foo 函数,导致了上下文对象的丢失,所以最终控制台的打印结果就是 global 。

    默认绑定

    默认绑定 规则应用于独立函数调用的时候,也可以看作是无法应用上述三种规则时的默认规则,该规则会将函数调用的 this 绑定到全局对象上面。

    var a = 2
    
    function foo() {
      console.log(this.a)
    }
    
    foo() // 2
    

    上述例子中,我们对 foo 函数进行了独立调用,所以它的 this 被默认绑定规则绑定到全局对象上面。

    但是该规则有一个需要注意的点就是,当 函数体 处于严格模式下时,this 会被绑定到 undefined:

    var a = 2
    
    function foo() {
      'use strict'
      console.log(this.a)
    }
    
    foo() // TypeError: Cannot read property 'a' of undefined
    

    箭头函数

    箭头函数 被单独拎出来说明是有原因的,因为箭头函数不遵循上述的四条规则,它是根据外层的作用域来决定 this 的,并且箭头函数的绑定是无法被修改的。

    var a = 2;
    
    var foo = () => {
      console.log(this.a)
    }
    
    var obj = {
      a: 4,
      foo: foo
    }
    
    obj.foo() // 2
    

    上述例子中,我们虽然是通过上下文对象 obj 进行的函数调用,但是箭头函数并没有受到隐式绑定规则的影响,所以控制台当中打印的结果为 2 。

    小结

    今天我们了解了 this 的绑定机制,要判断 this 的指向必须从函数的调用位置下手。找到函数调用之后可以顺序应用以下的四条规则进行判断:

    1. new 调用,绑定到新创建的对象。
    2. call 或者 apply 调用,绑定到指定的对象上。
    3. 由上下文对象调用,绑定到上下文对象上。
    4. 独立调用,在严格模式下绑定到 undefined ,否则绑定到全局对象上。

    当同个函数包含多种调用方式时,应用规则的 优先级 也是按照上述的排序。

    最后记得 箭头函数 不应用上述的四条规则,它的 this 指向受所处的作用域决定。


    起源地下载网 » 前端面试之JavaScript基础(二)—— this

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元