最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • js的this的原理以及用法

    正文概述 掘金(天天学前端)   2021-07-29   405

    ​js的this指向是工作中最常碰到的,同时也是笔试 or 面试中会被问到的问题,故在本文整理了js的this指向,以供参考。

    此篇以面试题开题,而后再讲JavaScript的this指向,最后以面试题结束。

    面试题

    var length = 10;
    
    function fn () {
        console.log(this.length);
    }
    
    var obj = {
        length: 5,
        method: function (fn) {
            fn();
            arguments[0]();
        }
    };
    
    obj.method(fn, 1);
    

    js的this的原理以及用法

    问:浏览器的输出结果是什么?

    它的答案是:先输出一个 10,然后输出一个 2。

    解析:

    1. 在这道题中,虽然 fn 作为 method 的参数传了进来,但它的调用者并不受影响,仍然是 window,所以输出了 10。
    2. arguments0;这条语句并不常见,可能大家有疑惑的点在这里。其实,arguments 是一种特殊的对象。在函数中,我们无需指出参数名,就能访问。可以认为它是一种,隐式的传参形式。
    3. 当执行 arguments0; 时,其实调用了 fn()。而这时,fn 函数中 this 就指向了 arguments,这个特殊的对象。obj.method 方法接收了 2 个参数,所以 arguments 的 length,很显然就是 2 了。

    this 是什么

    this 是 JavaScript 中的一个关键字。它通常被运用于函数体内,依赖于函数调用的上下文条件,与函数被调用的方式有关。它指向谁,则完全是由函数被调用的调用点来决定的。

    所以,this,是在运行时绑定的,而与编写时的绑定无关。随着函数使用场合的不同,this 的值也会发生变化。但是有一个总的原则:那就是this 总会指向,调用函数的那个对象。

    js中的this指向

    如何判断this指向?可以按照下面的顺序来进行判断:

    // 1. 函数是否在new中调用(new绑定) ?如果是的话,this绑定的是新创建的对象。
    var bar = new foo();
    
    // 2. 函数是否通过call、apply(显示绑定)或者硬绑定(bind)调用?如果是的话,this绑定的是指定的对象。
    var bar = foo.call(obj2);
    
    // 3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。
    var bar = obj1.foo();
    
    // 4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到全局对象
    var bar = foo();
    

    js的this的原理以及用法

    不理解什么是new绑定显示绑定硬绑定隐式绑定默认绑定?没关系,看下面 ↓:

    1. 默认绑定。在严格模式下绑定到undefined,否则绑定到全局对象。

    解释:

    最常用的函数调用类型是:独立函数调用。可以把这条规则看做是无法应用其他规则时的默认规则。如:

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

    js的this的原理以及用法

    在本例中,foo函数调用时应用了默认绑定,因此this指向全局对象,而声明在全局作用域中的变量(比如 var a = 2)就是全局对象的一个同名属性,所以在调用foo()时,this.a被解析成了全局变量a。

    那么,我们是怎么知道这里应用了默认绑定呢?

    在代码中,foo()函数时直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则。

    如果使用严格模式(strict mode),则不能将全局对象用于默认绑定,因此this会绑定到undefined:

    function foo() {
      "use strict";
      console.log(this.a);
    }
    var a = 2;
    foo(); // 会报错。TypeRrror: this is undefined。
    

    js的this的原理以及用法

    这里还有一个非常重要的细节,虽然this的绑定规则完全取决于调用位置,但是只有foo()运行在非strict mode下时,默认绑定才能绑定到全局,在严格模式下调用foo()则不影响默认绑定:

    function foo() {
      console.log(this.a);
    }
    var a = 2;
    (function () {
      "use strict";
      foo(); // 2
    })()
    

    js的this的原理以及用法

    一般来讲,不应该在代码中混合使用strict模式和非strict模式。整个程序要么严格要么非严格。然而,有时候可能会用到第三方库,其严格程度和自己的代码有所不同,因此一定要注意这类兼容性细节。

    2. 隐式绑定。由上下文对象调用,绑定到那个上下文对象。

    解释:

    确定调用位置是否有上下文对象,或者说是否被某个对象拥有或包含,如:

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

    js的this的原理以及用法

    调用位置会使用obj上下文来引用函数,因此,可以说函数被调用时obj对象“拥有”或“包含”它。

    当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因此this.aobj.a是一样的。

    对象属性引用链中只有上一层或者说最后一层在调用位置中起作用,如:

    function foo() {
      console.log( this.a );
    }
    
    var obj2 = {
      a: 42,
      foo: foo,
    }
    
    var obj1 = {
      a: 2,
      obj2: obj2,
    }
    
    obj1.obj2.foo(); // 42
                    
    

    js的this的原理以及用法

    隐式丢失

    被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定绑定,从而把this绑定到全局对象或者undefined上。如下:

    function foo() {
      console.log(this.a);
    }
    
    var obj = {
      a: 2,
      foo: foo
    }
    
    var bar = obj.foo; // 函数别名
    var a = 'global'; // a 是全局对象的额属性
    bar(); // 'global'
    

    js的this的原理以及用法

    虽然bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。

    在传入回调函数时,也会发生隐式丢失:

    function foo () {
      console.log(this.a);
    }
    function doFoo (fn) {
      // fn 其实引用的是foo
      fn();
    }
    
    var obj = {
      a: 2,
      foo: foo
    }
    
    var a = 'global';
    doFoo( obj.foo ); // 'global'
    

    js的this的原理以及用法

    和上一个例子一样,fn引用的是foo函数本身,因此此时的fn()其实是一个不带任何修饰的函数调用,因此应用了默认绑定。

    在js环境中内置的setTimeout()函数实现和下面的伪代码类似:

    function setTimeout(fn, delay) {
      // 等待delay毫秒
      fn();
    }
    

    js的this的原理以及用法

    所以传递给定时器的函数,也会应用默认绑定。

    3. 显示绑定。由call/apply/bind显示绑定,绑定到执行的对象。

    解释:

    可以使用callapply方法显式的指定this的绑定对象,如:

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

    js的this的原理以及用法

    通过foo.call(...),我们可以在调用foo时强制把它的this绑定到obj上。

    硬绑定

    通过callapply仍然无法解决绑定丢失的问题,但是通过显示绑定的一个变种可以解决这个问题,如:

    function foo() {
      console.log(this.a);
    }
    
    var obj = {
      a: 2
    }
    
    var bar = function () {
      foo.call(obj);
    }
    
    bar(); // 2
    setTimeout(bar, 100); // 2
    bar.call( window ); // 2。强制绑定的bar不可能再修改它的this。
    

    js的this的原理以及用法

    为什么会出现这样的情况呢?

    是由于我们创建了函数bar(),并在它的内部手动调用了foo.call(obj),因此强制把foothis绑定到了obj。无论之后如何调用函数bar,它总会手动在obj上调用foo。这种绑定是一种显式的强制绑定,因此我们称之为硬绑定

    由于硬绑定是一种非常常用的模式,所以ES5提供了方法bind,使用方法:

    function foo(something) {
      console.log(this.a, something);
      return this.a + something;
    }
    var obj = {
      a: 2,
    }
    var bar = foo.bind(obj);
    var b = bar(3);// 2 3
    console.log(b); // 5
    

    js的this的原理以及用法

    bind 会返回一个新函数,它会把指定的参数设置为this的上下文并调用原始函数。

    4. new绑定。由new调用,绑定到新创建的对象。

    解释:

    使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作:

    1. 创建(构造)一个全新的对象。
    2. 这个新对象会被执行[[Prototype]]连接。
    1. 这个新对象会绑定到函数调用的this。
    2. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
    function foo(a) {
      this.a = a;
    }
    var bar = new foo(2);
    console.log(bar.a); // 2
    

    js的this的原理以及用法

    使用new来调用foo(...)时,我们会构造一个新对象并把它绑定到foo(...)调用中的this上。

    注意:ES6中的箭头函数不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定this,具体来说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么)。这其实和ES6之前的代码中的self=this机制一样。

    另一道面试题

    最后,让我们来巩固一下 this 的概念和用法。来看一道面试题:

    window.val = 1;
    
    var obj = {
        val: 2,
        dbl: function () {
            this.val *= 2; 
            val *= 2;       
            console.log('val:', val);
            console.log('this.val:', this.val);
        }
    };
    
     // 说出下面的输出结果
     obj.dbl();
     var func = obj.dbl;
     func();
    

    js的this的原理以及用法

    答案是输出:2 、 4 、 8 、 8。

    解析:

    1. 执行 obj.dbl(); 时, this.val 的 this 指向 obj,而下一行的 val 指向 window。所以,由 window.val 输出 2,obj.val 输出 4 。
    2. 最后一行 func(); 的调用者是 window。所以,现在的 this.val 的 this 指向 window。
    1. 别忘了刚才的运算结果,window.val 已经是 2 了,所以现在 this.val *= 2; 的执行结果就是 4。
    2. val *= 2; 的执行结果,就是 8 了。所以,最终的结果就是输出 8 和 8 。

    最后听一首悦耳的歌放松放松,回忆学到的东西。

    点击下面js的this的原理以及用法js的this的原理以及用法​播放音乐

    徐心愉 - 热爱105°C的你 (完整女声版).mp3 00:00 03:15#让生活多一点生机

    长按二维码关注,一起努力。

    js的this的原理以及用法

    js的this的原理以及用法

    助力寻人启事

    js的this的原理以及用法

    js的this的原理以及用法

    微信公众号回复 加群 一起学习。


    起源地下载网 » js的this的原理以及用法

    常见问题FAQ

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

    发表评论

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

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

    联系作者

    请选择支付方式

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