进击的 JavaScript(六) 之 this

记得刚开始,我理解 this 的时候 也是云里雾里的,哈哈,希望通过这篇文章,对你有帮助吧。

关于 this 最多的说法,就是:谁调用它,this就指向谁。这话呢,不能说它错了,只能说它讲的不严谨,为什么呢?我们先来了解下 this 的几种绑定规则。

一、默认绑定

默认绑定 发生在全局环境 。

全局环境中,this 默认绑定到 window。(严格模式下一样)

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

"use strict";    //使用严格模式执行代码
var a = 666;
console.log(this.a)

//666


二、隐式绑定

隐式绑定 发生在 方法调用(执行)。

什么是方法呢?通常把 对象的属性值 是函数的,称为方法。

var obj = {
    fun: function(){}
}

//这里obj 对象里 的fun 属性值是个函数, 就把 这个fun 属性称为方法了。

通常,方法调用时,this 隐式绑定到其 所属的对象 上。

var a = "window";

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

obj.fun();

//"obj"

来个难一点的:

var obj1 = {
    a: "obj1",
   
    obj2: {
        a: "obj2",
        fun: function(){
            console.log(this.a);
        }
    }
}

obj1.obj2.fun();

//"obj2"

这里的答案 跟你想的一样吗? 出现这个答案的关键 就是于,fun 函数 在作为对象方法执行时, this 绑定的是它的 所属对象,也就是 obj2 。 而非外层 的 obj1

三、隐式绑定丢失

在判断是否是隐式绑定的时候,最容易出问题的地方就是发生在 隐式绑定丢失。

隐式丢失是指被隐式绑定的函数丢失绑定对象,从而绑定到window。这种情况容易出错却又常见。(严格模式下,绑定到undefined)

隐式绑定丢失 一般 发生在 函数独立调用时。

啥是独立调用呢?就是一个简单的函数执行. 函数名的前面没有任何引导内容。

function ff(){};

ff();   //独立调用

当函数独立调用(执行)时,this 就会隐式绑定丢失,而绑定到 window 对象上。(非严格模式下)

function fun(){
    console.log(this === window);
}
fun();
//true

那么严格模式下呢?是指向 undefined 的。

function fun(){
    "use strict";    //使用严格模式执行代码
    console.log(this);
}
fun();

//undefined

考考你:

var a = "window";

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

var fun2 = obj.fun;

fun2();
//"window"

判断是否隐式绑定丢失的关键就在于, 判断函数 是否是哪种调用。

上面的例子,关键点就在 最后两行代码。
先看其中的第一行:

var fun2 = obj.fun;

这里把 obj 的fun 方法 赋值给了 一个变量 fun2,这里的 fun 并没有作为对象的方法来执行,因为,fun 方法这里没有执行。

其后:

fun2();

再执行 fun2,它保存着 fun1 方法,这时候执行 fun2(等于fun1) ,但是,它是独立调用。因为,没有作为对象的方法来调用。所以 this 就被指向 window了。

那么怎么解决隐式丢失问题呢?

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
        return function(){
            console.log(this.a);
        }
    }
}

obj.fun()();

//"window"

//这里我们想要的是 obj里 a 的值,可是,隐式绑定丢失导致获取到了 window 里 a 的值。

可以基础好的已经知道答案了:

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
        var that = this;
        return function(){
            console.log(that.a);
        }
    }
}

obj.fun()();

//"obj"

因为 fun 是作为方法调用的,所以 this 绑定到 obj 对象上,因此,我们就可以先用一个变量 that 来保存 this,然后 在内部的 匿名函数中 使用 that 就可以了。它保存着 上面 this 的绑定对象。

忽然灵机一动,想出个题目,看人家都玩出题,我也试试,哈哈:

var a = "window";

function fun(){
    var a = "fun";

    return (function(){
        return this.a;
    })()
}

fun()

//“你猜”

这道题中 有立即执行函数、this问题,哈哈,乍一看挺恶心,其实看完上面的,应该可以看出来的。

四、显示绑定

通过call()、apply()、bind()方法把 this 绑定到对象上,叫做显式绑定。对于被调用的函数来说,叫做间接调用

var a = "window"

var obj = {
    a:"obj",
}

function fun(){
    console.log(this.a);
}

fun.call(obj);
//"obj";

这里使用了 call 方法,把fun 中的 this 绑定到 obj 对象上。

javascript内置的一些函数,具有显式绑定的功能,如数组的5个迭代方法:map()、forEach()、filter()、some()、every(),以及创建对象的 Object.create() 函数(后面原型链中会细说),都可以手动绑定this。

大家可以去看下API文档,数组的这几个函数的最后一个参数,就是指定函数内 this 的绑定,如果不指定,则是window,严格模式下是undefined

var a = [1,2,3];

a.forEach(function(){
    console.log(this)
},a);

//绑定 this  为 a 这个数组

//(3) [1, 2, 3]
//(3) [1, 2, 3]
//(3) [1, 2, 3]

五、new 绑定

如果 使用 new 来创建对象,因为 后面跟着的是构造函数,所以称它为构造器调用。对于this绑定来说,称为new绑定。

想知道 构造器调用 中 this 的绑定,就要知道 new 到底做了啥了。

先来个 new 的实现。看不懂不要紧,在后面原型链那篇,还会说的。

function New(proto){  //proto 为传进来的构造函数
    var obj = {};
    obj.__proto__ = proto.prototype;

    proto.apply(obj, Array.prototype.slice.call(argument,1));
    //你这要看懂这步就行。这里把构造函数里的 this  绑定到了 新的obj 对象上,最后 返回了该新对象,作为实例对象。

    return obj;
}

所以在使用 new 来创建实例对象时,new 内部把 构造函数的 this 绑定到 返回的新对象 上了。

function Person(name){
    this.name = name;
}
var c = new Person("zdx");
c.name;

总结: this的四种绑定规则:隐式绑定、隐式绑定丢失、显式绑定和new绑定,分别对应函数的四种调用方式:方法调用、独立调用、间接调用和构造器调用。


附录:

1、关于this绑定 的优先级问题。

简单提一下吧:

new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定

2、ES6 中,箭头函数的 this 绑定。

箭头函数内的 this 绑定的 是所属的环境(函数或者对象), 它是固定不变的。

先看下上面的这个例子

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
        return function(){
            console.log(this.a);
        }
    }
}

obj.fun()();

//"window"

上面我们使用 一个变量来保存 this 的绑定,下面我们来用 箭头函数解决问题

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
        return () => {
            console.log(this.a);
        }
    }
}

obj.fun()();

//"obj"

实际上,箭头函数内部是没有this 的,所以,它不能使用 new 构造器调用,call显示绑定。所以它内部就是使用了一个变量来保存 箭头函数 所属环境的(函数或者对象) this

就相当于:

var a = "window";

var obj = {
    a: "obj",
    
    fun: function(){
            that = this;
            return function(){
                console.log(that.a);
            }
    }
}

obj.fun()();

//"obj"

考考你:

var a = "window";

var obj = {
    a: "obj",
    
    fun1: function(){
        return () => {
            console.log(this.a);
        }
    }
}

var fun2  = obj.fun1;

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

推荐阅读更多精彩内容

  • 本文主要内容参考此文章,主要是为了记录 产品需求 用户从qq/微信分享出去的H5页面,当点击H5页面的某个按钮时,...
    _CLAY_阅读 9,864评论 0 2
  • 书,是人类最好的朋友,也是我们一生中不可缺少的一部分。书是人类的好老师,让我们从中获得很多知识。书还能在我...
    小羽_235c阅读 138评论 0 0
  • 安卓开发过程中难免会碰到需要选择日期时间的情况,由于大部分android初级教程都没教怎么选择时间,初学者碰到这种...
    篱开罗阅读 11,335评论 4 44
  • 孩子是一个独立的个体,TA从脱离母体的那一刻,就是一个独立的人。但是很多父母认为孩子小,总喜欢替孩子定目标,拿主意...
    苹果Apple来了阅读 226评论 0 1