JavaScript this指向问题详解

this 的指向

1.函数调用

在 ES5 中,其实 this 的指向,始终坚持一个原理:this 永远指向最后调用它的那个对象

var name = "windowsName";
var a = {
name: "Cherry",
fn : function () {
console.log(this.name); // Cherry
}}
window.a.fn();


    var name = "windowsName";
    var a = {
        name : null,
        // name: "Cherry",
        fn : function () {
            console.log(this.name);      // windowsName
        }
    }

    var f = a.fn;
    f();

虽然将 a 对象的 fn 方法赋值给变量 f 了,但是没有调用,“this 永远指向最后调用它的那个对象”,由于刚刚的 f 并没有调用,所以 fn() 最后仍然是被 window 调用的。

默认绑定

独立函数调用 中 this 指向全局对象

如果使用严格模式 (strict mode), 那么全局对象将无法使用默认绑定, 因此 this 会绑定 到 undefined

隐式绑定

考虑调用位置是否有上下文对象, 或者说是否被某个对象拥有或者包含

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

obj.foo(); // 2

无论是 直接在 obj 中定义还是先定义再添加为引用属性, 这个函数严格来说都不属于 obj 对象.
然而, 调用位置会使用 obj 上下文来引用函数, 因此你可以说函数被调用时 obj 对象“拥有”或者“包 含”它

但是当foo()被调用时, 它的落脚点确实指向 obj 对象. 当函数引用有上下文对象时, 隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象. 因为调用foo()时 this 被绑定到 obj, 因此this.aobj.a是一样的

对象属性引用链中只有最后一层会影响调用位置:

2. 自执行函数

自执行函数中的this永远是window

(function () {
    console.log(this); //this -> window
})();
~(function () {
    console.log(this); //this -> window
})();

3. 事件绑定

  • DOM 零级事件绑定
oDiv.onclick = function () {
    // this -> oDiv
    ajax()// this -> window
};
  • DOM 二级事件绑定
function ajax(content) {
  console.log('ajax request ' )
  console.log(this)
}

oDiv.addEventListener(
    'click',
    function () {
        console.log(this)// this -> oDiv
        ajax()//this  -> window

    },
    false
);

改变 this 的指向

  • 使用 ES6 的箭头函数
  • 使用 applycallbind
  • new 实例化一个对象
var name = "windowsName";

var a = {
    name : "Cherry",

    func1: function () {
        console.log(this.name)     
    },

    func2: function () {
        setTimeout(  function () {
            this.func1()
        },100);
    }

};

a.func2()     // this.func1 is not a function

调用 setTimeout 的对象是 window,但是在 window 中并没有 func1 函数。

箭头函数

ES6 的箭头函数是可以避免 ES5 中使用 this 的坑的。箭头函数的 this 始终指向函数定义时的 this(词法作用域),而非执行时。

(1)“箭头函数中没有 this 绑定,必须通过查找作用域链来决定其值“

var name = "windowsName";

var a = {
    name : "Cherry",

    func1: function () {
        console.log(this.name)     
    },

    func2: function () {
        setTimeout( () => {
            this.func1()
        },100);
    }

};

a.func2()     // Cherry

(2)若上一层并不存在函数,this指向又是谁?

let btn2 = document.getElementById('btn2');
let obj = {
    name: 'kobe',
    age: 39,
    getName: () => {
        btn2.onclick = () => {
            console.log(this); // this -> window
        };
    },
};
obj.getName();

使用 apply、call、bind

详情在以下连接

https://chun53.top/358.html

call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略

let obj = {
    birth: 1990,
    getAge: function (year) {
        let fn = year => year - this.birth; // this.birth -> 1990
        return fn.call({ birth: 2000 }, year); // 第一个参数被忽略,this.birth -> 1990
    },
};
console.log(obj.getAge(2018)); // 28

使用构造函数调用函数

https://chun53.top/272.html

 

阅读剩余
THE END