4

一直以来都知道js的this让初学者很困惑, 但由于在学angularjs的时候潘老师早早的就教我们写代码时先定义self = this , 然后通过操作self, 再之后学习angular又一直使用的箭头函数, 所以js的this用起来和java的用起来并没有什么不同, 也就没有认真的去学习js的this和其他语言的到底独特在那里, 本周遇到了一个函数尽然不能使用箭头函数, 又想起了这个问题, 就找了几篇博客学了学。

感受一下

让我们先看几段js代码,并猜猜打印的是什么

下面的环境都为chrome的控制台, 即非严格模式(即不使用 use strict, 两种模式下结果不相同)
// 例子1
function a(){
    name: 'yunzhi_a';
    console.log(this); //?
}
a();

// 例子2
var b = {
    name:"yunzhi_b",
    fn:function(){
        console.log(this)  //  ?
    }
}
b.fn();

// 例子3
var c = {
    name:"yunzhi_c",
    fn:function(){
        console.log(this); // ?
    }
}
window.c.fn();

// 例子4
var d = {
    name: 'yunzhi_d',
    o: {
        name: 'object',
        fn: function(){
            name: 'fn'
            console.log(this); // ?
        }
    }
}
var j = d.o.fn;
j();

是不是感觉他们都差不多?
公布答案之前, 先说一下this的使用的规则:

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁实际上this的最终指向的是那个调用它的对象

例子的答案

例子1

image.png答案是Window,为什么呢?想想上面的规则,**this的最终指向的是那个调用它的对象**,函数没有调用对象,这时this将指向全局的window对象。

例子2

第二个应该很简单了,还是上面的规则,这次是b调用的fn,所以嘛
image.png

例子3

第三个呢,是谁调用的fnwindow吗?再想想
image.png
复习一下,this的最终指向的是那个调用它的对象, fn()是通过谁调用的,是c调用的,所以打这时的this指向的就是c

例子4

看着和上面是差不多的对吧?所以答案就是o对吧?不对
image.png
再看看, 我们调用的是j,虽然他是通过fn赋的值,但我们确实调用的是前面没有对象的j, 在例子1中已经说过了,此时会this会指向window

箭头函数中的this

在使用箭头函数时我们不会遇到这种让人晕乎的this指向问题

箭头函数保持它当前执行上下文的词法作用域不变,而普通函数则不会。换句话说,箭头函数从包含它的词法作用域中继承到了this的值。
var object = {
    data: [1,2,3],
    dataDouble: [1,2,3],
    double: function() {
        console.log("this inside of outerFn double()");
        console.log(this);    // object
        return this.data.map(function(item) {
            console.log(this);      // window
            return item * 2;
        });
    },
    doubleArrow: function() {
        console.log("this inside of outerFn doubleArrow()");
        console.log(this); // object
        return this.dataDouble.map(item => {
            console.log(this);      // objecgt
            return item * 2;
        });
    }
};
object.double();
object.doubleArrow();

是不是对map中的函数是谁调用的感到疑惑了?为什么是window
因为map中的函数是一个匿名函数,他并没有调用者,想到上面的例子了吧,我们可以看一下map的基本实现

// Array.map polyfill
if (Array.prototype.map === undefined) {
    Array.prototype.map = function(fn) {
        var rv = [];
        for(var i=0, l=this.length; i<l; i++)
            rv.push(fn(this[i]));
        return rv;

直接使用的fn()

严格模式对this的影响

this在严格模式下指向undefined
大部分情况下,开发者使用 this ,并不希望它指向全局 window 对象。严格模式帮我们在使用this关键词时,尽量少做搬起石头砸自己脚的蠢事。

修改this指向

开发者可以通过bindcall apply来主动控制this的指向,当然这里不再细说,有兴趣可以看这篇文章——JS中call、apply、bind使用指南,带部分原理。

参考文章

彻底理解js中this的指向,不必硬背。
[译] 深入浅出 JavaScript 关键词 -- this


笙歌会停
1k 声望45 粉丝

代码成就万世基积沙镇海 梦想永在凌云意意气风发