在刚开始学 JavaScript
时,最深恶痛绝的三个 JS怪👹:this妖、原型精和 AJAX魔
最近在写总结回顾时竟意外发现这三大怪早已在不知不觉中被我消化吸收了,趁着热乎记下来✍~~~
有请今天的出场嘉宾🎤:this妖
this妖 的前世今生
假设现在有一对象🐘🐘
var person = {
name: 'April-cl',
age: 18,
sayHi: function(){
// 待补充
}
}
我想要调用 person.sayHi(…),打印出「你好,我是 April-cl,今年 18 岁」
emmmmmmmmm 我要怎样写 sayHi
呢,这样吗?
sayHi: function(name, age){
console.log('你好,我是 ${name},今年 ${age} 岁')
}
调用方式:person.sayHi(person.name, person.age)
这似乎可以,但是…看起来傻傻的😳
那要不,给 sayHi
传入一个对象?代码改成这样:
sayHi: function(self){
console.log('你好,我是 ${self.name},今年 ${self.age} 岁')
}
调用方式:person.sayHi(person)
心里嘀嘀咕:可我就想把参数里的 person
省掉
💡 有了,给参数里的 person
穿上隐身衣。可是没有了实参,sayHi
声明的形参怎么办?
好办,给 self
也穿上隐身衣,用一个驻守的小妖精 this
来代替:
sayHi: function(){
// this 就是 self
console.log('你好,我是 ${this.name},今年 ${this.age} 岁')
}
调用方式:person.sayHi()
现在看着明了了,this
是 sayHi
隐藏的第一个形参。在调用 person.sayHi()
时,这个 person
会「变成」 this
令小白闻风丧胆的 this妖 现身啦
俗话说知彼知己方能百战百胜,那就先要了解 this
的5种绑定方式
- 默认绑定
- 隐式绑定
- 显示绑定
- new绑定
- 箭头函数绑定
默认绑定
前置知识(系统丢给了你一本秘籍 📓 ):
在全局块级作用域
- 所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员
- 非严格模式下 this 指向 window
- 用 let 或 const 声明不会被绑定到 window 上
好了,接下来打怪升级 ⬆
var a = 1
let b = 2
function foo () {
console.log('foo a:' + this.a)
console.log('foo b:' + this.b)
}
console.log('this a:' + this.a)
console.log('this b:' + this.b)
foo()
根据秘籍
a
和 foo
变量会被绑定在 window
上,而 b
则不会(即 window.b
是 undefined
),而 this
指向 window
,所以答案是
this a:1
this b:undefined
foo a:1
foo b:undefined
隐式绑定
回顾上文『this妖 的前世今生』,this
隐式绑定的对象其实就是穿了隐身衣的 person
✨ Get 新秘籍:当函数引用有上下文对象时, 如 obj.foo() 的调用方式, foo 内的 this 指向 obj
但是江湖险恶,若是有人披着层「马甲」诓骗 this妖,就会造成 this妖 和穿着隐身衣的正主形同陌路,请看题:
function foo () {
console.log(this.a)
};
var obj = { a: 1, foo };
var a = 2;
var foo2 = obj.foo;
obj.foo();
foo2();
打开照妖镜(控制台),会发现此时结果
1
2
???
不难理解 obj.foo()
的结果是 1,但 foo2()
居然打印出的是window
下的 a
😮
这便是这层「马甲」的厉害之处了:使用另一个变量来给函数取别名造成丢失绑定对象(秘籍升级 ⬆︎ )
显式绑定
嘿嘿 😏 你有张良计,我有过墙梯 ~
拿出哆啦A梦的道具『非生物催眠喇叭📢』: call
apply
bind
function foo () {
console.log(this.a)
};
var obj = { a: 1, foo };
var a = 2;
var foo2 = obj.foo;
obj.foo();
foo2();
foo2.call(obj) // 上面代码与隐式绑定示例一致,新增此行代码
当当当,foo2.call(obj)
打印出的是 1。
这就是利用 call
、 apply
或者 bind
方法改变函数内this的指向的显示绑定。
MDN Function.prototype.apply()
new绑定
使用new来调用一个函数,会构造一个新对象并把这个新对象绑定到调用函数中的this
这里留坑,等关于 new
的博客写好了再来填
箭头函数绑定
实际上箭头函数里并没有 this,如果在箭头函数里看到 this,直接把它当作箭头函数外面的 this 即可。外面的 this 是什么,箭头函数里面的 this 就还是什么,因为箭头函数本身不支持 this。
参考文章: