this 全面解析

this 的指向

this 是在函数被调用时发生的绑定,它指向什么完全取决于函数在哪里被调用

注意: this 不指向函数本身,也不指向函数的词法作用域

绑定规则

  • 默认绑定

无法应用其他规则时的默认规则

        function foo(){
            console.log(this.a);
       }
        var a  = 3;
        foo(); // 3
// foo() 是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定(注意是在非严格模式下,若启动严格模式,默认绑定不会绑定到全局函数)   

// foo()指向全局对象,所以foo()中的this是在全局对象中调用的,this.a 被解析成了全局变量 a,  
  • 隐式绑定

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


        function foo() {
            console.log(this.a);
        }
        var obj = {
            a: 8,
            foo: foo
        }
        var obj2 = {
            a: 4,
            obj: obj
        }
        obj.foo() ; // 8
        obj2.obj.foo(); // 8
//var obj={ foo: foo } ,obj对象内部包含了一个指向函数的属性,并通过这个属性间接引用函数,即表示foo 函数被 obj 上下文引用了

// 当函数引用有上下文时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象,即 foo 中的 this 会绑定到 obj 上,此时 this.a = obj.a 

// 对象属性引用链中只有上一层(最后一层)在调用位置中起作用

隐式绑定的问题是:被隐式绑定的函数会丢失绑定对象,即会应用到默认绑定

        function foo() {
            console.log(this.a);
        }
        var obj = {
            a: 8,
            foo: foo
        }
        var a = 0;
        var b = obj.foo;
        b(); // 0
  // b 引用的是 foo 函数本身,此时丢掉了绑定的对象,即 b() 其实是一个不带任何修饰的函数调用,因此 this 指向全局对象    
  • 显示绑定

使用 call(obj) 或 apply (obj,argu) 把函数绑定到 obj上去

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

// 当使用foo.call(obj) 时,foo就会把它的 this 强制绑定到 参数obj上

// 若参数是一个原始值,则它会转换成它的对象形式,叫做“装箱”

为了解决丢失绑定的问题 ,我们提出了一种 “硬绑定”

        function foo() {
            console.log(this.a);
        }
        var obj = {
            a: 8,
        }
        var a = 9;
        var bar = function(){
            foo.call(obj);
        }
        bar(); //8 
// 每次调用bar(),都会在 obj 上调用 foo         
        setTimeout(bar,100);
        bar.call(window); //  8
// 这里没有输出 9,说明硬绑定的 bar 不可以再修改它的 this        

ES5 bind()
bind(obj) 会返回一个硬编码的新函数,它会把你指定的参数设置为 this 的上下文并调用原始函数

        function foo() {
            console.log(this.a);
        }
        var obj = {
            a: 8,
        }
        var a = 9;
        var bar = foo.bind(obj);
        bar(); //8 
  • new 绑定

使用 new 来调用函数时,会自动执行下面的操作:

1.创建一个全新的对象
2.这个新的对象会被执行 prototype 操作
3.这个新的对象会绑定到函数调用的 this
4.如果这个函数没有返回其他对象,那么 new 表达式中的函数调用会自动返回这个新对象

        function foo(a) {
            this.a = a;
        }

        var a  = 9;
        var bar = new foo(8);
        console.log(bar.a); //8 

// 使用 new 来调用 foo()时,我们会构造一个全新的对象并把它绑定到 foo()调用中的this 上,即把 bar 绑定到 foo 的 this 上,所以 bar.a = foo 中的 this.a (bar.a)

四种绑定的优先级

new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定

箭头函数的 this 的规则

箭头函数不是使用 function 关键字定义的,故 this 不遵循以上的四种规则,而是根据外层作用域来决定 this

        function foo(a) {
           return (a)=>{
               console.log(this.a);
           };
        }
        var obj1 = {a:1};
        var obj2 = {a:2};
        var bar = foo.call(obj1); 
        bar.call(obj2); // 1 
// foo() 内部创建的箭头函数会捕获调用时 foo()的 this,由于foo() 的 this 绑定到了 obj1上,bar (foo返回的参数,即箭头函数)的 this 也会绑定到 obj1上

// 箭头函数的绑定无法修改 (new 也无法修改)      

猜你喜欢

转载自blog.csdn.net/twfkxp/article/details/79819831