正文
今天在学js的时候,发现了一些奇奇怪怪的错误,研究了一下,发现有点意思,就记录了下来。
var apple = {
label: 'apple',
print: function() {
console.log(this.label)
}
}
var banana = {
label: 'banana',
print: function() {
console.log(this.label)
}
}
(apple.print = banana.print)()
这道题输出的结果是什么呢?
如果你在第一层,会认为结果是 banana,如果稍加思考分析,会认为是undefined, 但是其实结果是
Uncaught TypeError: Cannot read property 'print' of undefined。
引起报错的原因是分号导致的,在js里面,如果行的开头是(, 会作为上一个语句的前缀,即上面等价为
var banana = {
label: 'banana',
print: function() {
console.log(this.label)
}
}(apple.print = banana.print)()
这时候apple.print = banana.print会被当作成入参去执行,但是这时候banana这个变量对象在执行上下文中还没赋值,只是进行了声明,所以banana是undefined,所以就会报上述的错。解决方案很简单,加个;就好了
let banana = {
label: 'banana',
print: function() {
console.log(this.label)
}
}
(apple.print = banana.print)()
我们换种姿势,把banana换成let的声明方式,这时候就会变成另外一个错误,
Uncaught ReferenceError: Cannot access 'banana' before initialization。
这里涉及的知识是变量提升和暂死区,通过var声明的变量banana,会在创建上下文的阶段进行变量提升,即把banana放进上下文的活动对象里面去,而通过let声明的变量,直到它们的定义被执行时才初始化,在之前都存在暂死区,如果在暂死区的时候被访问,就会报错ReferenceError。
再改一下
var banana = {
label: 'banana',
print: function() {
console.log(this.label)
}
}
(apple.print = apple.print)()
同样没有分号,这时的报错换了一个花样
Uncaught TypeError: {(intermediate value)(intermediate value)} is not a function
这是因为相对于第一次的错误,apple已经赋值过了,所以不会报undefined的错误,所以这时候程序接着执行,发现
{
label: 'banana',
print: function() {
console.log(this.label)
}
}
不是一个函数,所以就报错了。
总结
JavaScript是世界上最好的语言。