昨天遇到的一道题,问输出结果是什么?为什么?如何更改可以输出另一个name?
var name = "Tom"
var obj = {
name:"Jerry",
getName:function(){
function get(){
console.log(this.name)
}
get()
}
}
obj.getName() //"Tom"
复制代码
首先我们先看看在函数内部调用this都会有哪些情况:
这里专门问这个输出值,第一直觉就想到会是输出Tom,否则就没必要问这么多。验证过后输出就是Tom,然后分析为什么。
为什么输出Tom?
首先输出的this.name的结果一定由this决定,不输出Jerry,那么this一定不是指向obj, 通过var声明的Tom,是在全局作用域可见,是附加在Window上的属性,输出为Tom,那很明显get()函数中的this是指向window的,这是输出Tom的直接原因。但是我们想知道的是更深层次的原因————为什么obj内部方法的this指向了全局?
这里我的理解就是函数声明提升,getName属性对应的方法本身的this指向obj是毫无疑问的,但是在方法体内部并没有直接打印name属性,而是通过再次声明另一个函数get来调用this进行打印。这里的get函数在js预编译时会声明提升至全局,因此其this指向为window。 此处的get()函数它是在getName属性被访问到时才会调用,被调用时其作为一个普通函数执行,在正常模式下就是指向window。
重点是我还是没太理清一些细节,发帖也顺便求助大佬
如何实现输出Jerry?
第一种就是箭头函数
var name = "Tom"
var obj = {
name:"Jerry",
getName:function(){
get = () => {
console.log(this.name)
}
get()
}
}
obj.getName() //Jerry
复制代码
箭头函数内的this自动指向回调函数外层的 this,箭头函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象,因此get的this会指向obj。
实现类似this绑定的功能,并不是箭头函数内部进行了绑定,而是箭头函数没有this,这也是箭头函数不能作为构造函数的原因。
剩下的几种实现(bind永久绑定get的this,或使用apply和call在调用时指定this指向)
bind绑定
var name = "Tom"
var obj = {
name:"Jerry",
getName:function(){
function get(){
console.log(this.name)
}
get.bind(this)()
}
}
obj.getName() //Jerry
复制代码
apply和call
var name = "Tom"
var obj = {
name:"Jerry",
getName:function(){
function get(){
console.log(this.name)
}
get.apply(this) //Jerry
//get.call(this) //Jerry
}
}
obj.getName()
复制代码