luckyyyyy / blog

William Chan's Blog
https://williamchan.me/
175 stars 28 forks source link

JavaScript中的this关键词 #16

Open luckyyyyy opened 7 years ago

luckyyyyy commented 7 years ago

JavaScript拥有一个名为this 的关键字,在JavaScript程序中的不同位置,this所引用的值会有所不同。 这其实是一件比较头疼的事,因为随着ES6的发布和NodeJS的搅和,这个概念可能会被混淆。 今天我们只说浏览器中的this

全局上下文中

这个还是比较好理解的,如果直接在代码中使用this,那么this === window。 所以下面两行赋值做的是同一件事,创建一个名为hello的全局变量。

console.log(this === window); // true

this.hello = 'hello world';
window.hello = 'hello world';

console.log(this.hello); // hello world
console.log(window.hello); // hello world
console.log(hello); // hello world

函数上下文中

在函数或是闭包中引用了this结果又会如何? 在这个没有任何嵌套的函数中,this的指向取决于你是否使用了严格模式。

简单的例子

function hello () {
    console.log(this === window); // true
    console.log(this); // object global
}

hello();
function hello () {
    "use strict";
    console.log(this === window); // false
    console.log(this); // undefined
}

hello();

在模块模式中

下面来看一下,在这种情况中,this的指向又发生了什么变化。

var hello = {
    init: function () {
        console.log(this); // references hello
    },
};

hello.init();

所以你可以向下面这样做,来封装一个模块。

var hello = {
    default: {
        base: 'www.baidu.com',
        limit: 20,
    },
    init: function (cfg) {
        var config = cfg || this.default;
        console.log(config);
    },
};

hello.init();

嵌套函数

在匿名函数中

var hello = {
    init: function () {
        setTimeout(function () {
            console.log(this); // window
        })
    },
};

hello.init();

ES6箭头函数中

在ES6箭头函数中,this和普通函数中的指向是不同的,他永远会跟随上下文。 所以我们不会在非严格模式下的匿名函数或者全局函数中遇到this指向window的情况了。

const hello = {
    init: function() {
        console.log(this === hello); // true
        setTimeout(() => {
            console.log(this === hello); // true
        })
    },
};

hello.init();

再复杂一点

const hello = {
    init: function() {
        'use strict';
        console.log(this === hello); // true
        const func = function () {
            console.log(this === undefined); // true
            setTimeout(() => {
                console.log(this === undefined); // true
            })
        }
        setTimeout(() => {
            console.log(this === hello); // true
        })
        setTimeout(function() {
            console.log(this === window); // true
        })
        func();
    },
};

hello.init();