今天写代码,偶遇到一个问题,其问题代码简化为:
var obj={
val:123,
getVal:function(){
return val;
}
}
然后,语句obj.getVal()
报错:
Uncaught ReferenceError: val is not defined
当时楞了一下,使用obj.getVal()
,前面是obj
,那么该方法内部this
应该确实是obj
才对,不存在找不到变量val
的情况。为什么会这样呢?
随后才反应过来:忘记加this
前缀:
var obj={
val:123,
getVal:function(){
return this.val; //加this前缀
}
}
还是受java语言影响太深,下意识认为val
之前会默认添加this
关键字,即如果在方法内部找不到val
,就会使用this.val
去类内部寻找“成员变量”,这种思想在JavaScript中显然不对。
实际上在JavaScript中,根据名称查找变量的一套规则是作用域。也就是说在执行obj.getVal()
时,尽管函数内部的上下文this
确实是obj
本身,但是如果不指定this.val
,那么它是不会在类中查找是否有此属性(也就不会在类中找不到时,再按照原型链上寻),它只会在当前函数作用域内查找,找不到则去外层作用域查找,直到全局作用域为止。
其实我觉得也很好理解:
试想在java语言中使用类方法,假定在类方法内出现一个变量,那么程序会先在当前代码块作用域内寻找,找不到就会在外层代码块内寻找,以此类推,若在整个方法中都不曾出现这个变量,那么它要不就是类的成员变量,要不就是错误。因此即便不加this
也无妨。
但是在JavaScript中它是函数作用域,因此像是之前的obj.getVal()
语句,它要不就运行在全局作用域中,要不就运行在另一个函数作用域中,所以,出现一个变量,如果当前函数未曾定义,就回去外层函数中寻找,以此类推,直到找到全局作用域为止。它不会自己添加this
的原因就很简单了:这并不是真正意义上,与java程序类似的类方法。一方面,哪怕getVal
不是obj
的类方法,只要调用时动态绑定this
,它就可以变成一个“类方法”;另一方面,就算是类方法,调用时解绑this
,它就不是一个类方法了。所以类方法只是在调用时绑定了this
指向这个类对象,除此之外,与其他普通函数并无区别,因为前面提到二者是可以相互转化的。
所以,除非你特别指定this
说明这是一个类属性,它会按照继承链寻找该变量之外,在没有this
情况下,当然不会在当前类对象中寻找了。
总结就是,写类方法时,引用类属性,总是要加this
关键字,千万别忘了,否则它就不会在类中寻找这个属性,而是按照嵌套作用域去找了。