javascript成神之路(4):深入理解this关键字,是的就是this


声明:本文转载自https://my.oschina.net/jinsanpang/blog/1604835,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

摘要:如果你真的理解了this是什么,那么你的web几乎所向披靡(文章后面有惊喜,不要错过)

很多程序员会这么认为,this关键字与面向对象程序开发紧密相关,其完全指向由构造器新创建的对象。在ECMAScript规范中也是这样实现的,但正如我们将看到那样,在ECMAScript中,this并不限于只用来指向新创建的对象。还有很多新功能特性

一、定义

this代表当前对象,说明this是在某种特定的情况下才是成立的,它是执行上下文的一个属性。

activeExecutionContext = { AEC: {...}, this: thisVal };

这里AEC是我们讨论的变量对象。this与上下文中可执行代码的类型有直接关系,this值在进入上下文时确定,并且在上下文运行期间永久不变。

二、全局代码中的this

在全局代码中,this始终是全局对象本身,这样就有可能间接的引用到它了。

// 显示定义全局对象的属性 this.ab = 10; // global.ab = 10 alert(ab); // 10 // 通过赋值给一个无标示符隐式 bb = 20; alert(this.bb); // 20 // 也是通过变量声明隐式声明的 // 因为全局上下文的变量对象是全局对象自身 var cc = 30; alert(this.cc); // 30

三、函数代码中的this

在这时候this值的首要特点是它不是静态的绑定到一个函数。this是进入上下文时确定,在一个函数代码中,这个值在每一次完全不同,但是在代码运行时的this值是不变的,也就是说,因为它不是一个变量,就不可能为其分配一个新值。

var F = {y: 10}; var Bar = { y: 20, test: function () { alert(this === Bar); // true alert(this.y); // 20 this = F; // 错误,任何时候不能改变this的值 alert(this.y); // 如果不出错的话,应该是10,而不是20 } }; // 在进入上下文的时候 // this被当成Bar对象 B.test(); // true, 20 F.test = Bar.test; // 不过,这里this依然不会是foo // 尽管调用的是相同的function F.test(); // false, 10

在我们通常的函数调用中,this是由激活上下文代码的调用者来提供的,即调用函数的父上下文(parent context )。this取决于调用函数的方式,正是调用函数的方式影响了调用的上下文中的this值,没有别的什么可以看到,即使是正常的全局函数也会被调用方式的不同形式激活,这些不同的调用方式导致了不同的this值。例如:

function F() { alert(this); } F(); // global alert(F === F.prototype.constructor); // true // 但是同一个function的不同的调用表达式,this是不同的 F.prototype.constructor(); // F.prototype

那么,调用函数的方式如何影响this值?请看下面

四、引用类型

引用类型的值只有两种情况: 1、当我们处理一个标示符时,2、或者一个属性访问器

在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。如果调用括号()的左边是引用类型的值,this将设为引用类型值的base对象(base object),在其他情况下(与引用类型不同的任何其它属性),这个值为null。不过,实际不存在this的值为null的情况,因为当this的值为null的时候,其值会被隐式转换为全局对象,例如:

function F() { return this; } F(); // global

我们看到在调用括号的左边是一个引用类型值(因为F是一个标示符)

var fooReference = { base: global, propertyName: 'foo' };

相应地,this也设置为引用类型的base对象。即全局对象

var F = { B: function () { return this; } }; F.B(); // F

我们再次拥有一个引用类型,其base是F对象,在函数B激活时用作this。

var FB = { base: F, propertyName: 'B' };

五、作为构造器调用的函数中的this

还有一个与this值相关的情况是在函数的上下文中,这是一个构造函数的调用。

unction A() { alert(this); // "a"对象下创建一个新属性 this.x = 10; } var a = new A(); alert(a.x); // 10

new运算符调用“A”函数的内部的[[Construct]] 方法,接着,在对象创建后,调用内部的[[Call]] 方法。 所有相同的函数“A”都将this的值设置为新创建的对象。

六、函数调用中手动设置this

在函数原型中定义的两个方法允许去手动设置函数调用的this值。它们是.apply和.call方法。他们用接受的第一个参数作为this值,this 在调用的作用域中使用。这两个方法的区别很小,对于.apply,第二个参数必须是数组(或者是类似数组的对象,如arguments,反过来,.call能接受任何参数。两个方法必须的参数是第一个——this。

var dog = { say() { console.log(this) } } var cat = {} dog.say.call(cat)

其中this通过call被绑定到了cat上

七、箭头函数

它的this指向与普通函数有很大的不同。箭头函数内部的 this 是词法作用域,由上下文确定。简单说就是箭头函数中的 this 只和定义它时候的作用域的 this 有关,而与在哪里以及如何调用它无关,同时它的 this 指向是不可改变的。

var obj = { x: 10, foo: function() { var fn = () => { return () => { return () => { console.log(this); //Object {x: 10} console.log(this.x); //10 } } } fn()()(); } } obj.foo();

对于箭头函数还需要注意一点,就是它的this确定后不会改变。使用call、apply、bind也无法改变它的this,因此使用它们传入的第一个参数无效。但是后面添加的参数值还是有效的。

更多分享请关注,微信公众号:xiaohumuhe13,或今日头条号:(大话前端),还能获得海量视频资源哦~

本文发表于2018年01月10日 10:32
(c)注:本文转载自https://my.oschina.net/jinsanpang/blog/1604835,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1708 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1