this在JavaScript中的应用

this

This是JavaScript函数的一个关键字。在全局上下文中(任意函数体外部),this指代全局对象,而在函数体内部,this指的是调用函数的那个对象。大多数情况下,函数的调用方式决定了this的值。下面,本文将对几种调用情境下this的用法做一个大致的介绍。

直接调用

在非严格模式下直接调用,this的值会被默认为全局对象,如下:

var x = 0
function f() {
    this.x = 1
}
f()
console.log(x)//打印结果为 1

以上这段代码中,this的值指代全局对象,函数运行时全局变量x被重新赋值为1,覆盖了第一次的赋值,最后打印结果为1。
在严格模式下,this将保持它进入执行环境时的值,如果上下文中没有定义,则它将会默认为undefined,如下:

var x = 0
function f() {
    "use strict";
    this.x = 1
}
f()
console.log(x)//执行时会报错:"Cannot set property 'x' of undefined"

同样的代码,加上"use strict"后,因为this的值是undefined,故在给this.x赋值时会发生错误。

对象方法中的this调用

当函数作为某个对象的方法调用时,this指代调用该函数的对象。

var o = {
    x: 1,
    f: function () {
        return this.x
    }
}
console.log(o.f())//打印结果为1

以上代码中,执行console.log(o.f())时,函数f被对象o调用,此时的this指代对象o。以上代码也可以写为如下的形式:

var o = {}
o.x = 1
o.f = function () {
    return this.x
}
console.log(o.f())//同样打印1

也即,用何种方式在何处定义对象的调用函数并不会影响到this的值,确定this的值仅需考虑对象o与函数f的调用关系。
此外需注意,当函数的调用存在多层嵌套时,this的值仅受最靠近的调用成员的影响。

var o = {
    x: 1,
    b: {
        x: 2,
        f: function () {
            return this.x
        }
    }
}
console.log(o.b.f())//打印结果为2

上述代码中的函数执行时,this指代离函数f最近的调用对象b。
另外,对于原型链中的this。如果一个方法是存在于一个对象的原型链中的,那么调用该方法时,this指的是调用这个方法的对象,如下:

var o = { }
o.f = function () {
    return this.a
}
var p = Object.create(o)
p.a = 1
o.a = 2
console.log(o.f())//打印结果为2,this指代o
console.log(p.f())//打印结果为1,this指代p
构造函数中的调用

当我们通过构造函数生成一个新对象时,this将与这个新对象绑定。

function f() {
    this.a = 1
}
var o = new f()
console.log(o.a)//打印结果为1

需要注意的是,当构造器的默认返回指是this引用的对象时,可以手动设置其他的返回对象。

function f() {
    this.a = 1
    return {b : 2}
}
var o = new f()
console.log(o.a)//打印结果为undefined
console.log(o.b)//打印结果为2

在调用函数的过程中,设置了返回对象,使得与this绑定的对象被取消。当返回值不是一个对象时,则返回this。

call和apply中的this

call()方法和apply()方法是函数从Function对象原型中继承的方法,这两个方法的作用一样,均是指定函数的调用对象,区别在于call()方法接受参数列表,而apply()方法接受一个包含多个参数的数组(或类数组对象)。当函数通过call()或apply()调用时,传递的第一个参数就是this,这个this也就是正在调用函数的那个对象。

a=3
b=4
function f() {
    sum =this.a +this.b
    console.log(sum)
}
var o = { a: 1, b: 2 }
f.call(o)//打印结果为3
f.apply(o)//打印结果为3
f.call()//打印结果为7
f.apply()//打印结果为7

当参数为空时,默认调用全局对象,故执行f.cal()与f.apply()的输出结果为7。
由此,可以获得一个启发,所有函数都可以转换为call形式来调用(或apply,下文仅讨论call),也即:

fun(parameters)//等价于
fun.call(undefined,parameters)
//---------------------------------
obj.child.method(parameters)//等价于
obj.child.method.call(obj.child,parameters)

统一表示为:

fun.call(context, parameters)

此处的context就是this。当需要判断函数的this为何值时,可以先将函数转换为call形式,对应的第一个参数context即为this。
需要注意的是,使用apply和call函数时,如果传递的this不是一个对象,那么JavaScript会尝试用内部的ToObject操作将其转换为一个对象。

function f() {
    console.log(Object.prototype.toString.call(this));
}
f.call('this')//打印结果为[object String]

函数执行时,this被转换为了一个String对象。

bind方法

bind()方法是EcmaScript5中引入的一个方法,它的作用是创建一个新的函数(被称为绑定函数)。新函数与被绑定的目标函数拥有相同的函数体,this被绑定到了bind()函数的第一个参数上,无论函数被如何调用都具有同样的this值。

var a = 0
var b = { a: 2 }
function f1() {
    return this.a
}
var f2 = f1.bind(b)
var o = { a: 1, f1: f1, f2: f2 }
console.log(o.f1())//打印结果为1,this为o
console.log(o.f2())//打印结果为2,this被绑定为b
var c = o.f1
console.log(c())//打印结果为0,this为全局变量
var d = o.f2
console.log(d())//打印结果为2,this依然为b
小结

以上,即为JavaScript中几种不同调用情境下this的不同应用。总而言之,当需要判断this的值是什么的时候,可以统一将函数转换为call或者apply的形式。而在DOM Event Handler中,jQuery Event Handler中,可以通过看源码中的函数是怎么被call或apply的,或者通过看文档,来确定this的值。如果实在无法确定,还有console.log大法,直接打印出来,this的值也就不再神秘了。

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

推荐阅读更多精彩内容