美文网首页
函数中this指向问题以及this四大绑定原则

函数中this指向问题以及this四大绑定原则

作者: ticktackkk | 来源:发表于2020-06-02 15:23 被阅读0次

一、

普通调用方式 => window

function fn() {
            console.log(this);
        }
        fn();

构造函数调用=> 实例对象,原型对象里面的方法也指向实例对象

 function Star(){  
        }
        Star.prototype.sing = function(){
            //...
        }
         var ldh = new Star();

对象方法的调用 => 该方法所指的对象

var o={
           hello:function (){
               console.log(this);
           }
       }
       o.hello();`

事件绑定方法 => 绑定事件对象

 var btn = document.querySelector('button');
        btn.onclick = function(){
            console.log(this);
        }

定时器函数 => window

       window.setTimeout(function(){
           console.log(this);
       },1000)
       window.setInterval(function(){
           console.log(this);
       },1000)

解决方法1
使用that获取btn的this指向

    //点击按钮使按钮三秒后可以再点击
    <button>确定</button>
    <script>
        var btn = document.getElementsByTagName('button')[0];
        btn.onclick = function () {
            var that = this;
            console.log(that);
            setTimeout(function () {
                that.disabled = false;
            }, 3000)
        }
  

解决方法1
bind()方法

 <button>确定</button>
    <script>
        var btn = document.getElementsByTagName('button')[0];
        btn.onclick = function () {

            console.log(that);
            setTimeout(function () {
                this.disabled = false;
            }.bind(this), 3000)
            相当于给定时器绑定了一个bind方法,
            这个方法不像call和apply一样会立即调用函数,
            并且让定时器里面的this指向了bind的this,
            但是bind的this是再定时器外面,在外面所以这个this指向btn
        }

立即执行函数=> window

(function(){
            console.log(this); 
        })()

二、this四大绑定原则

默认绑定

function foo() { 
     console.log( this.a );
 } 
 var a = 2; 
foo(); // 2
声明在全局作用域中的变量(比如 var a = 2)就是全局对 象的一个同名属性。它们本质上就是同一个东西,并不是通过复制得到的,就像一个硬币 的两面一样。
接下来我们可以看到当调用 foo() 时,this.a 被解析成了全局变量 a。为什么?因为在本 例中,函数调用时应用了 this 的默认绑定,因此 this 指向全局对象。
那么我们怎么知道这里应用了默认绑定呢?可以通过分析调用位置来看看 foo() 是如何调 用的。在代码中,foo() 是直接使用不带任何修饰的函数引用进行调用的,因此只能使用 默认绑定,无法应用其他规则。
如果使用严格模式(strict mode),那么全局对象将无法使用默认绑定,因此 this 会绑定 到 undefined:
function foo() {  
    console.log( this.a );
 } 
var a = 2; 
(function(){ 
     "use strict"; 
    foo(); // 2  
})();
这里有一个微妙但是非常重要的细节,虽然 this 的绑定规则完全取决于调用位置,但是只 有 foo() 运行在非 strict mode 下时,默认绑定才能绑定到全局对象;严格模式下与 foo() 的调用位置无关:

隐式绑定

另一条需要考虑的规则是调用位置是否有上下文对象,或者说是否被某个对象拥有或者包 含,不过这种说法可能会造成一些误导

function foo() { 
     console.log( this.a );
 } 
var obj = { 
     a: 2,     foo: foo 
 }; 
obj.foo(); // 2
首先需要注意的是 foo() 的声明方式,及其之后是如何被当作引用属性添加到 obj 中的。 但是无论是直接在 obj 中定义还是先定义再添加为引用属性,这个函数严格来说都不属于 obj 对象。
然而,调用位置会使用 obj 上下文来引用函数,因此你可以说函数被调用时 obj 对象“拥 有”或者“包含”它。
无论你如何称呼这个模式,当 foo() 被调用时,它的落脚点确实指向 obj 对象。当函数引 用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。因为调 用 foo() 时 this 被绑定到 obj,因此 this.a 和 obj.a 是一样的

显式绑定

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

JavaScript 中的“所有”函数都有一些有用的特性(这和它们的 [[ 原型 ]] 有关——之后我 们会详细介绍原型),可以用来解决这个问题。具体点说,可以使用函数的 call(..) 和 apply(..) 方法。严格来说,JavaScript 的宿主环境有时会提供一些非常特殊的函数,它们 并没有这两个方法。但是这样的函数非常罕见,JavaScript 提供的绝大多数函数以及你自 己创建的所有函数都可以使用 call(..) 和 apply(..) 方法。

new绑定

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

使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
1. 创建(或者说构造)一个全新的对象。
2. 这个新对象会被执行 [[ 原型 ]] 连接。
3. 这个新对象会绑定到函数调用的 this。
4. 如果函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象。
使用 new 来调用 foo(..) 时,我们会构造一个新对象并把它绑定到 foo(..) 调用中的 this 上。new 是最后一种可以影响函数调用时 this 绑定行为的方法,我们称之为 new 绑定。

如何来判断this

现在我们可以根据优先级来判断函数在某个调用位置应用的是哪条规则。可以按照下面的 顺序来进行判断:
1. 函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象
var bar = new foo()
2. 函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是 指定的对象。
var bar = foo.call(obj2)
3. 函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上 下文对象。
var bar = obj1.foo()
4. 如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到 全局对象。
var bar = foo()
就是这样。对于正常的函数调用来说,理解了这些知识你就可以明白 this 的绑定原理了。 不过……凡事总有例外。

小结

如果要判断一个运行中函数的 this 绑定,就需要找到这个函数的直接调用位置。找到之后 就可以顺序应用下面这四条规则来判断 this 的绑定对象。
1. 由 new 调用?绑定到新创建的对象。
2. 由 call 或者 apply(或者 bind)调用?绑定到指定的对象。
3. 由上下文对象调用?绑定到那个上下文对象。
4. 默认:在严格模式下绑定到 undefined,否则绑定到全局对象。
一定要注意,有些调用可能在无意中使用默认绑定规则。如果想“更安全”地忽略 this 绑 定,你可以使用一个 DMZ 对象,比如 ø = Object.create(null),以保护全局对象。
ES6 中的箭头函数并不会使用四条标准的绑定规则,而是根据当前的词法作用域来决定 this,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这 其实和 ES6 之前代码中的 self = this 机制一样。

以上皆来自你不知道的JavaScript上卷this全面解析部分

相关文章

  • 函数中this指向问题以及this四大绑定原则

    一、 普通调用方式 => window 构造函数调用=> 实例对象,原型对象里面的方法也指向实例对象 对象方法...

  • JavaScript中的this指向

    在全局中使用 this指向Window 函数中的this 谁调用函数指向谁 这里指向Window 事件绑定中的th...

  • this指向以及react中绑定this

    JavaScript函数中的this 我们都知道JavaScript函数中的this不是在函数声明的时候定义的,而...

  • javascript:this到底是什么?

    被误解的this 1.this指向自身 2.this指向它的父函数 如何判断函数中this的绑定 this不是在编...

  • JS中的this指向问题

    1. this的几种绑定方法 (1)普通函数中的this指向函数的调用点 (2) call明确绑定 (3)bind...

  • this指向以及作用域和闭包

    一、关于this指向的几种场景 1、默认绑定(函数直接调用) 非严格模式下,默认绑定指向全局(node 中是 gl...

  • js中关于this全面解析和this的指向问题

    this指向原则每个函数的this是在调用的时候被绑定的,完全取决于函数的调用位置。 1、 调用位置 调用位...

  • JavaScript中this的绑定

    this绑定的规则 1.默认绑定 独立函数调用 在浏览器中foo()函数时保存在window对象中,所以指向的是w...

  • this全面解析

    1 定义 谁调用的函数,该函数的this就指向谁。 2 四种绑定规则 2.1 默认绑定,this指向全局对象,严格...

  • this深入理解

    js中this指向有几种情况 全局环境 函数调用 构造调用 apply、call、bind绑定 箭头函数 全局环境...

网友评论

      本文标题:函数中this指向问题以及this四大绑定原则

      本文链接:https://www.haomeiwen.com/subject/bqyuzhtx.html