你真的懂js中的this?

banner.jpg

1. 为什么要用this?

thisjs中最为复杂的机制之一。大部分开发者写了很久的js代码都可能没有主动使用过this,或者遇到就直接"忽略",但其实this本质上提供了一种更加优雅的方式来传递对象引用,可以使代码更加简洁和易于复用,所以全面了解this是有必要的。

2. this的误解

在学习this之前,先来说说它的两个误区。第一个就是this并不是指代本身,这里是因为用了词法作用域才会出现这样的理解;第二个就是this的绑定和声明没有任何关系,它取决于调用时候的条件。

3. this的理解

this的绑定是在调用的时候确定下来的,和声明没有任何关系。

3.1. this绑定规则(4个)

this绑定规则有五个,分别是:默认绑定,隐式绑定,显式绑定,new绑定。

3.1.1. 默认绑定

独立函数调用,无法应用其他规则的时候使用的默认规则。这个规则根据会根据严格模式非严格模式绑定不一样的值,严格模式use strict绑定的是undefined,而非严格模式绑定的是全局对象(浏览器就是window)。

// 非严格模式
function foo() {
  console.log(this);
}
foo(); // window

// 严格模式
function bar() {
  'use strict'
  console.log(this);
}
bar(); // undefined

3.1.2. 隐式绑定

第二个this绑定的规则就是隐式绑定,其实就是调用的位置是否有上下文对象。来看下面这个例子:

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

var obj = {
  a: 1,
  foo: foo
};
obj.foo(); // 1

这里调用foo函数的方式是通过obj.foo(),使这个函数被调用的时候加上了obj这个上下文对象,隐式绑定这个规则会把函数中的this绑定到obj这个对象上,因此this.aobj.a是一样的。

多个层级引用

大多数情况下,调用函数的层级都不是简单的一层,如果出现多层的话,函数中的this会绑定在哪一个对象上?例如:obj1.obj2.obj3.foo(),可以看下面的例子:

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

var obj2 = {
  a: 2,
  foo: foo
};

var obj1 = {
  a: 1,
  obj2: obj2
};
// 多个对象引用函数的this会绑定在上一层或者最后一层的属性上
obj1.obj2.foo(); // 2

这个例子中的foo中的this绑定在obj2对象上,也就是说函数中的this绑定在上一层或者最后一层对象属性上。

隐式丢失

隐式绑定还有一个比较常见的问题就是this绑定时会丢失绑定对象,这样this会应用默认绑定规则,绑定到全局对象或者undefined上,这取决于是否严格模式(use strict)。

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

var obj = {
  a: 1,
  foo: foo
};
var f = obj.foo; // 这里f是obj.foo的引用,引用的是foo函数本身
f(); // undefined;

上面例子中的fobj.foo的引用,也就是foo函数本身,当执行f函数时,相当于直接执行f()foo函数中的this应用默认绑定规则,把当前函数内的this绑定到全局对象上(window)。

这里还有一个关于setTimeout经典的例子:

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

var obj = {
  a: 'obj的a属性',
  foo: foo
}

var a = '全局变量a';
setTimeout(obj.foo,0); // '全局变量a'

这里传入setTimeout的其实是obj.foo引用的函数本身,也就是f函数,那么这个时候也是应用默认绑定规则,函数里的this会绑定到全局对象上。其实回调函数丢失this绑定是非常常见的,所以在处理回调函数的this绑定时候要注意。

3.1.3. 显式绑定

显式绑定一般使用的就是applycallbind这几个方法,其中applycall都是调用函数并且把它的this绑定在方法的第一个参数上,这两个方法的区别在于其他参数上。而bind也会绑定this到第一个参数对象上,但并不执行该函数。

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

var obj = {
  a: 'obj的a属性'
};
foo.apply(obj); // 'obj的a属性'

这里使用foo.apply(obj)显式地绑定foo函数里面的thisobj对象上,foo函数里的this.a也就是obj.a

apply和call

applycall通过第一个参数影响函数里面的this绑定,但有时候第一个参数并不是普通的对象。

function foo() {
  console.log(this.toFixed(2));
}

foo.apply(3); // 3.00

apply方法里面的3明显不是对象,那在apply执行后,函数里面的this会被转换成new Number(3),所以最终执行的就是new Number(3).toFixed(2)输出结果是3.00applycall如果第一个参数传入原始值(数字,字符串,布尔值)来绑定this对象,那么this绑定的当前值是(new Number()new Boolean()new String()) 。

还有一种特殊情况就是,applycall第一个参数传入nullundefined,那么函数中的this绑定被忽略,使用默认绑定规则,this绑定在全局对象或者undefined(这个取决于是否严格模式)。

bind

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

var obj = {
  a: 'obj的a属性'
};

var f = foo.bind(obj);
f('f的参数'); // obj的a属性 f的参数

bind()会返回一个新的函数,并且会为函数的this绑定到第一个参数上。

3.1.4. new绑定

js中,构造函数其实是使用new操作符时调用的函数,构造函数并不属于某个类,实际上也不会实例化一个类,构造函数就是一个使用new操作符调用的普通函数。

function Foo(a) {
  this.a = a;
}

var f = new Foo(1);
console.log(f.a); // 1

这里的new操作符调用Foo()函数时,内部会创建一个新的对象并把它绑定到Foo()调用的this上,如果这个函数没有其他返回值对象,那么函数就会自动返回这个新对象。

3.2. 箭头函数的this

上面介绍的this绑定的四个规则已经可以包含所有“正常“的函数。但是ES6中的箭头函数却无法使用这些规则。箭头函数的this是根据外层作用域来决定的。来看看箭头函数的词法作用域:

function foo() {
  return () => {
    console.log(this);
  }
}

var obj = {
  a: 'obj的a属性'
};

var f = foo.call(obj);
f(); // {a: 'obj的a属性'}

上面的f()输出的并不是window全局对象,而是obj对象,因为在调用foo函数的时候使用了call方法显式绑定到obj属性上,而foo函数的返回值是箭头函数,那么这个返回的箭头函数里面的this绑定就是外层foo函数执行时绑定的obj对象上,所以这里的箭头函数的this最终绑定在obj对象上。

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

推荐阅读更多精彩内容