一谈到this,很多让人晕晕乎乎的抽象概念就跑出来了,这里我就只说最核心的一点——函数中的this总指向调用它的对象,接下来的故事都将围绕这一点展开
(提醒前排的筒子们准备好茶水和西瓜,我要开始讲故事啦!!)
【故事】有一个年轻人叫"迪斯"(this),有一天,迪斯不小心穿越到一个叫 “伽瓦斯克利”(javascript)的 异世界,此时此刻迪斯身无分文, 他首先要做的事情就是——找到他的住宿的地方——调用函数的对象
this的默认绑定
【故事——线路1】如果迪斯(this)直到天黑前都没有找到能收留自己的住所,他眼看就要过上非洲难民的生活, 这时候,一位乐善好施的魔法师村长——window救世主一般地出现了:先住在我家吧!
【正文】
当一个函数没有明确的调用对象的时候,也就是单纯作为独立函数调用的时候,将对函数的this使用默认绑定:绑定到全局的window对象
function fire () { console.log(this === window) } fire(); // 输出true
上面的例子我相信对大多数人都很简单,但有的时候我们把例子变一下就会具有迷惑性:
function fire () { // 我是被定义在函数内部的函数哦! function innerFire() { console.log(this === window) } innerFire(); // 独立函数调用 } fire(); // 输出true
函数 innerFire在一个外部函数fire里面声明且调用,那么它的this是指向谁呢? 仍然是window
许多人可能会顾虑于fire函数的作用域对innerFire的影响,但我们只要抓住我们的理论武器——没有明确的调用对象的时候,将对函数的this使用默认绑定:绑定到全局的window对象,便可得正确的答案了
下面这个加强版的例子也是同样的输出true
var obj = { fire: function () { function innerFire() { console.log(this === window) } innerFire(); // 独立函数调用 } } obj.fire(); //输出 true
【注意】在这个例子中, obj.fire()的调用实际上使用到了this的隐式绑定,这就是下面我要讲的内容,这个例子我接下来还会继续讲解
【总结】 凡事函数作为独立函数调用,无论它的位置在哪里,它的行为表现,都和直接在全局环境中调用无异
this的隐式绑定
【故事——线路2】 迪斯(this)穿越来异世界“伽瓦斯克利”(javascript)的时候,刚好身上带了一些钱,于是他找到一个旅馆住宿了下来
当函数被一个对象“包含”的时候,我们称函数的this被隐式绑定到这个对象里面了,这时候,通过this可以直接访问所绑定的对象里面的其他属性,比如下面的a属性
var obj = {
a: 1,
fire: function () {
console.log(this.a)
}
}
obj.fire(); // 输出1
现在我们需要对平常司空见惯的的代码操作做一些更深的思考,首先,下面的这两段代码达到的效果是相同的:
// 我是第一段代码 function fire () { console.log(this.a) } var obj = { a: 1, fire: fire } obj.fire(); // 输出1 // 我是第二段代码 var obj = { a: 1, fire: function () { console.log(this.a) } } obj.fire(); // 输出1
fire函数并不会因为它被定义在obj对象的内部和外部而有任何区别,也就是说在上述隐式绑定的两种形式下,fire通过this还是可以访问到obj内的a属性,这告诉我们:
1. this是动态绑定的,或者说是在代码运行期绑定而不是在书写期
2. 函数于对象的独立性, this的传递丢失问题
(下面的描述可能带有个人的情感倾向而显得不太严谨,但这是因为我希望阅读者尽可能地理解我想表达的意思)
隐式绑定下,作为对象属性的函数,对于对象来说是独立的
基于this动态绑定的特点,写在对象内部,作为对象属性的函数,对于这个对象来说是独立的。(函数并不被这个外部对象所“完全拥有”)
我想表达的意思是:在上文中,函数虽然被定义在对象的内部中,但它和“在对象外部声明函数,然后在对象内部通过属性名称的方式取得函数的引用”,这两种方式在性质上是等价的(而不仅仅是效果上)
定义在对象内部的函数只是“恰好可以被这个对象调用”而已,而不是“生来就是为这个对象所调用的”
借用下面的隐式绑定中的this传递丢失问题来说明: