JavaScript this关键字

背书

JavaScript由于其运行期绑定的特性,this 的具体指向取决于函数的调用方式

  • 作为函数调用
  • 作为对象方法调用
  • 作为构造函数调用
  • 使用 apply 或 call 调用

但是无外乎一个原则:*this指向的永远是当前调用函数的那个对象 *。

下面围绕着这四种调用方式中this的不同含义展开叙述

函数调用

函数最常见的调用方式的方式就是全局调用,此时this就指向全局对象Global(浏览器中为window对象,nodejs中全局对象为global object)

function func1() {
    return this;
}
alert(func1() === window);//true

为了证明this就是全局对象,我们再来一个小例子

var x = 1;  
function test(){  
  this.x = 0;  
}  
test();
console.log(x);//0

上面的代码test()可以理解为window.test(),this.x=0实际上是将window.x进行了修改

严格模式中,函数的this值为undefined,因为严格模式中禁止this关键字指向全局对象。
发生直接函数调用时,函数的this指向全局对象,接下来执行this.x=xx,相当于隐式的声明了一个全局对象x,有时候会带来副作用

我们再来看一个小例子,也是一道经典的笔试题

var value = 2;
var myObj = {  
    value: 3  
};  
var add = function(a,b){  
    return a+b;  
};  
myObj.double = function(){  
  
    var helper = function(){  
        this.value = add(this.value,this.value);  
        alert(this.value)  
    };  
    helper();
};  

myObj.double();

请求,上面这道题的输出是什么的?

如果你的答案是6那么久成功掉进this陷阱了,正确的答案是4,解释一下原因:

以上代码达不到目的,因为函数调用时,helper函数的内部this被绑定到了全局变量(不信你可以打印一下这个this)。这是语言设计上的一个错误,倘若语言设计正确,那么当内部函数被调用时,this应该绑定到外部函数的this变量。这个设计错误的后果就是方法不能利用内部函数来帮助它工作,因为内部函数的this被绑定了错误的值,所以不能共享该方法对象的访问权。

幸运的是,有一个很容易的解决方案:如果该方法定义了一个变量并给他赋值this,那么内部函数就可以通过那个变量访问到this. 按照约定,我们可以把那个变量命名that:

var myObj = {  
    value :3  
};  
var add = function(a,b){  
    return a+b;  
};  
myObj.double = function(){  
    var that = this;//解决办法,将myObj这个正确的this缓存起来  
  
    var helper = function(){  
        that.value = add(that.value,that.value);  
        alert(that.value)  
    };  
    helper();//以函数的形式调用,this指向window全局对象  
};  
//以方法的形式调用,this指向调用者,这里是myObj对象  
myObj.double();//6  

作为对象方法的调用

此时this指向这个上级对象。

var x = 0;
function test(){  
 console.log(this.x);
}  
var o = {};  
o.x = 1;  
o.m = test;  
o.m(); // 1 

作为构造函数调用

如果一个函数前面带上一个new来调用,那么将会创建一个连接到该函数的prototype属性的新对象,同时函数的this会绑定到那个新对象上

function test(){  
  this.x = 1;  
}  
var o = new test();  
console.log(o.x); // 1  

上面调用 new test()的时候,test()中的this会指向一个空对象,这个对象的原型会指向test.prototype。

再来看一个稍微复杂点的例子

function Func1(){  
    this.a = 37;  
}  
var o = new Func1();  

console.log(o.a)//37

function Func2(){
    this.a= 37; 
     
    return{
        a:38
    };  
}   
o = new Func2();   
console.log(o.a)// ?

这个题目比较特殊,因为Func2 中return了一个新的对象,所以this绑定到了新返回的对象中,输出38

一个函数总会有一个返回值,如果没有明确指定则返回undefined

apply调用

apply()是函数对象的一个方法,允许切换函数执行的上下文环境,即 this 绑定的对象。也就是说apply调用可以改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。因此,this指的就是这第一个参数。apply()的参数为空时,默认调用全局对象

var x = 0;  
function test(){  
  console.log(this.x);  
}  

var o={};  
o.x = 1;  
o.m = test;  
o.m(); //1,this指向o
o.m.apply(); //0 this指向window
o.m.apply(o); //1 this指向o

再看个简单的例子

function add(c, d) {
    return this.a + this.b + c + d;
}
var o = {
    a: 1,
    b: 3
};
add.apply(o, [5, 7]); // 1 + 3 + 5 + 7 = 16

形象点,就是说调用add函数的时候,add函数中有些数据无法直接获取,需要其他对象,如O的帮助,所以add临时把自身的身份证交给o,让o临时帮助add完成操作。

一些关于this的陷阱和实践

  • setTimeout

setTimeout的执行环境跟调用它的函数的执行环境是分离的,隐刺setTimeout调用的函数中的this关键字指向的是window或global对象

var name = 'somebody';
var angela = {
    name: 'angela',
    say: function () {
        alert("I'm " + this.name);
    }
};

angela.say();//I'm  angela
setTimeout(angela.say, 1000);  //I'm  somebody

还有,有些DOM的事件回调函数中,可能涉及到setTimeout(),例如:

$('#myElement').click(function() {

    setTimeout(function() {

        // 这个this指向的是settimeout函数内部,而非之前的html元素

         $(this).addClass('aNewClass');

  }, 1000);

});

应对之策还是上文提到的聪明的that

$('#myElement').click(function() {
     var that = this;   //设置一个变量,指向这个需要的this

   setTimeout(function() {

        // 这个this指向的是settimeout函数内部,而非之前的html元素

     $(that).addClass('aNewClass');

    }, 1000);

});

写在后面

本文是在阮老师的文章基础加上了我自己的一些想法,强烈推荐阮老师的系列文章

其他文章推荐

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容