关键字:js name 变量 关键字 保留字 window 全局 属性
一、问题的诞生
今天有同学在复习js基础知识时,遇到一个问题,颇为疑惑,便来与我讨论。同样作为前端小白的我,在看到问题并在Chrome浏览器控制台进行多次尝试之后,我也陷入了跟他一样的懵逼状态。我的灵魂不禁发出了一连串的疑惑:”这是个啥?“”为什么会这样?“
问题如下:
var name = ["今","天","晴","天"];
console.log(name.join("-"));
乍一看,问题贼简单。但是把它放到谷歌浏览器控制台里输出一下后,他就变得不那么简单了。
var name = ["今","天","晴","天"];
console.log(name.join("-")); // Uncaught TypeError: name.join is not a function
没错,你没看错!它报错了!(报错截图如下👇)
这明明是个数组,为什么调用数组的 join 方法居然会报错呢?
而且,我又尝试检测了一下这个name变量的数据类型,检测结果居然为”string“。我的疑惑瞬间更大了:它是什么时候,又是怎么样变成字符串类型的呢??
我知道等号后边的数据肯定是个数组,但为什么会发生这个问题呢?
二、对问题的分析
我又进行了其它的尝试,随着尝试次数增多,我终于发现了问题的症结所在:当我把变量名更换成其它的非关键字和保留字时,一切都是正常的;但是就是这个name,无论后边放的是什么,只要数据类型是引用类型值,检测数据类型的返回结果都是字符串类型。而且,我们直接在控制台输入name或者window.name时,输出了一个空字符串。
嗯~ o(* ̄▽ ̄*)o 问题忽然变得有趣了起来!
那么,这个问题是怎么导致的呢?很明显,经过我们的测试之后,基本可以把问题的症结归咎于变量名name身上。
但是,name既不是关键字,也不是保留字呀?!
(截图来自MDN参考文献:developer.mozilla.org/zh-CN/docs/… )
三、找到问题发生的根源
于是带着这些疑惑,我翻阅了很多博客论坛,终于在”颖_恋“的CSDN博客里找到了一篇关于这个问题的解释。(颖_恋 的CSDN博客地址见文末)
原来,虽然name既不是关键字,也不是保留字,但是name作为变量是有其特殊之处。
在Safari,Chrome,Firefox和Opera这些Webkit内核的浏览器中,都给函数定义了一个非标准的name属性,它是window的自带全局属性,所以在用 var 声明变量name时,由于var声明变量时会在window上同时添加一个同名的属性,因此在全局声明name变量名时会出现访问异常问题。
当然,由于IE浏览器的特立独行,这个问题在IE的Trident内核的浏览器上并不会发生。虽然IE的window上也有name属性。(这么看来,IE浏览器还是有些优势的!😂)
四、问题的解决
问题找到了,也知道是什么原因造成的了。那这个问题怎么解决或者避免其发生呢?根据我们的经验,一般可以通过以下几种方法解决:
- 将 var 换成ES6新增的 let 。—— 由于var声明变量时,会同时在window全局上新增一个name属性;但我们其实根本用不到这个name属性;而let在声明变量时并不会像var一样在window上新增属性名。因此我们可以使用let来声明变量name。
- 将 var 声明的 name 变量放到闭包里。—— 闭包的作用之一就是可以保护变量,防止变量的相互污染。将 var 声明的变量 name 放到闭包中之后,name就变成了闭包里的私有变量了,便不会再与window上的name属性发生相互干扰了。
- 其实,最简单的方法就是换个变量名,只要不是关键字、保留字和这个特殊的name,把变量名换成任何其他的名称都不会再出现这个问题了。
五、写在最后
首先,感谢发现在这个问题并与我进行讨论的某同学(处于隐私保护,在此不具名了)。
其次,感谢网友 颖_恋 和他的CSDN博客。(博客地址:blog.csdn.net/line233/art… )。
最后,如果这篇文章帮到了你,麻烦您能给个关注或者写个评论。如果文章中有错误与不足之处,烦请诸位不吝赐教。在此一并表示感谢!🤞