js中this指向问题总结

1. 默认绑定规则

(1) 全局作用下 this指向window
console.log(this);
(2) 函数独立调用下 this指向window
function test(){
console.log(this);
}
test()

2. 隐式绑定规则

  • object.fun() 对象的方法,this指向调用这个方法的对象

函数执行,this才会指向,才有意义,每一个函数执行都会有一个自身的this指向。 函数不执行,this没意义。每个this都代表着函数的执行。

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

答案
obj.foo()方法执行 到 log(this) 此时的this指向调用这个方法的对象obj
test() 函数执行, 此时是函数的独立调用,因此this指向window

  • 函数立即执行语句: 在浏览器中this指向window
 // 立即执行函数
    // 第一种写法(function(){})()
    (function(){
        console.log(this);  
    })();
    // 第二种写法(function(){}())
    (function(){
        console.log(this);
    }())
  • 案例
var a = 0;
    var obj = {
        a: 2,
        foo: function(){
            function test(){
                console.log(this); 
            }
            return test;
        }
    }
    obj.foo()()

答案:this指向window
分析: obj.foo()执行完毕返回test,然后变成了test()这仍是以一个函数的独立调用,所以this指向window

  • 变量赋值的情况
var a = 0;
    function foo(){
        console.log(this);
    }
    var obj = {
        a: 2,
        foo: foo
    }
    obj.foo()  //  指向obj

    var bar = obj.foo;   //指向window
    bar()

答案分析:
改代码等价于

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

obj.foo() 这属于对象的方法调用,所以this指向调用该方法的对象obj
2)

//var bar = obj.foo 等价于
var bar = function(){
console.log(this)
}
bar() //这属于函数的独立调用,所以this指向window

(5) 参数赋值

 var a=0;
    function foo(){
        console.log(this);
    }
    function bar(fn){
        console.log(this);  //这个是函数bar的this 指向window
        fn()}
    var obj = {
        a:2,
        foo:foo
    }
    bar(obj.foo)

答案分析
此时obj.foo是一个形参, 代表foo函数 所以fn()就等于foo() 属于独立调用,this指向window

3. 显示绑定(强绑定)

call(this指向的对象,参数1,参数2…)
apply(this指向的对象,[参数1,参数2…])
bind(this指向的对象)(参数1,参数2…)

undefine、 null无包装类,如果将其作为this指向对象则绑定失败,采用默认的绑定方式window

4. new绑定

function Person(){
//构造函数 和new一起使用才起效果
}
new Person()
new的执行步骤

  1. 创建一个新的内存空间,放入一个空的对象

  2. 将this指向这个对象

  3. 执行构造函数的代码,为对象创建属性和方法

  4. 返回创建的对象

  5. this绑定的优先级
    new绑定>显式绑定>隐式绑定>默认绑定
    (1) 默认绑定规则优先级最低
    (2)隐式和显示的比较

 // 优先级的比较
    function foo(){
        console.log(this);
    }
    var obj1 = {
        a:2,
        foo:foo
    }
    var obj2 = {
        a:3,
        foo:foo
    }
    // 1. 隐式绑定
    // obj1.foo()
    // 2. 显示绑定
    obj1.foo.call(obj2)
    obj2.foo.call(obj1)

结果
{a: 3, foo: ƒ}
{a: 2, foo: ƒ}
结果显示
obj1.foo.call(obj2) 前半部分属于隐式绑定,后又用了显式绑定,this指定了显式绑定的对象,因此,显式绑定的优先级>隐式绑定
(3)显式绑定和new 绑定的比较

 function foo(b){
        this.a = b

    }
    var obj1 = {};
    var bar = foo.bind(obj1)
    bar(2)

    console.log(obj1.a);
    var baz = new bar(3);
    console.log(obj1.a);

    console.log(baz.a);

答案分析
var bar = foo.bind(obj1) 属于函数的赋值,并且this强制指向了obj1
bar(2) 执行bar ,将2传入foo函数,执行obj1.a = 2
log(obj1.a) 输出2
var baz = new bar(3) new中this指向的是新创建的对象baz,bar强制指向了obj1,因为new的优先级>显式绑定,所以this指向了baz,执行baz.a = 3;
所以在输出obj1.a为2. baz.a =3

6. 箭头函数的this

(参数1, 参数2)=>{
函数体)
=>代表了function关键字

(1)
箭头函数的内部并没有this指向,箭头函数的this指向是由外层函数的作用域决定的。

   var a = 0;
    function foo(){
        // var that = this;
        console.log(this);
         var test = () => {
            console.log(this);
        }
        test(); 
    }
    var obj1 = {
        a:2,
        foo:foo
    }
    obj1.foo();  

输出结果: this指向了obj1
{a: 2, foo: ƒ}
{a: 2, foo: ƒ}

(2)

var a = 0;
        function foo() {
            console.log(this);
            var test = () => {
                console.log(this);
            }
            return test;
        }
        var obj1 = {
            a: 1,
            foo: foo
        }
        var obj2 = {
            a: 2,
            foo: foo
        }
        obj1.foo()();

分析:
此时的obj1.foo()执行第一个log(this)this指向obj1,并返回test ,即得到test()独立调用函数,但是默认绑定规则对箭头函数无效,因此test函数体内的this并不指向window,箭头函数没有this,它只能那他的父级作用域所指向的this,因此依旧指向obj1

(3)
var obj1 = {
a: 1,
foo: ()=>{
console.log(this);
}
}

    obj1.foo()

答案分析:
如果foo不是箭头函数,那么this指向obj1, 但是因为箭头函数内部没有this指向,因此取其父级找,这里的父级是全局,所以this指定window

总结:
所有的this绑定对箭头函数不适用
箭头函数内部的this指向取决于其父级的this(保持一致)

练习
// 综合大练习

var name = 'window'
    var obj1 = {
        name:'1',
        fn1: function(){
            console.log(this.name);
        },
        fn2: () => console.log(this.name),
        fn3: function(){
            return function(){
                console.log(this.name);
            }
        },
        fn4: function(){
            return () => console.log(this.name);
        }
    }
    var obj2= {
        name:'2'
    }
    obj1.fn1()
    obj1.fn1.call(obj2);

    obj1.fn2()
    obj1.fn2.call(obj2)

    obj1.fn3()()
    obj1.fn3().call(obj2)
    obj1.fn3.call(obj2)

    obj1.fn4()()
    obj1.fn4().call(obj2)
    obj1.fn4.call(obj2)()

答案解析:
obj1.fn1() 隐式绑定,this指向obj1 所以this.name = obj1.name = ‘1’
obj1.fn1.call(obj2) 显示绑定, this强制指向obj2, 所以this.name = obj2.name = ‘2’
obj1.fn2() 和 obj1.fn2.call(obj2)
fn2 方法是箭头函数,没有自己的this指向,各种绑定均失效,其this取决于其父级,这里父级是全局作用域,因此this.name = window.name = window

obj1.fn3()() 其中obj1.fn3()是调用函数,返回值为一个函数f,
function(){
console.log(this.name);
}
f()为再调用这个函数,为单独函数调用,this指向window返回window
obj1.fn3().call2 可以这样理解
var foo = obj.fn3 = function (){ log(this.name)} 函数的声明
obj1.fn3.call(oj2)它改变的是fn3这个父级的this指向,但返回的仍是一个函数f ,f()调用仍为函数的单独调用 返回window

fn4: function(){
return () => console.log(this.name);
}

var foo = obj1.fn4();
即 foo = () => console.log(this.name) 函数的定义
obj1.fn4()() == foo() 箭头函数 其父级fn4,fn4是通过隐式绑定this指向obj1 ,所以返回obj1.name = ‘1’
obj1.fn4().call(obj2) == foo.call(obj2) 仍未箭头函数,各种绑定失效,返回其父级的指向 obj1 返回‘1’
obj1.fn4.call(obj2)() == foo.call() 但是强制将foo的父级fn4的指向到了obj2 返回obj2.name = ‘2’

你可能感兴趣的:(javascript,前端,ecmascript)