难道status只能是字符串吗?想想status当初设计出来的初衷,它就是为了临时在状态栏展示一些用户信息,所以必须是字符串。这样理解的话就顺理成章了。
所以我们看到使用status来定义变量是不可行的,除非定义的status是string类型,但是有的人就说,经常用status,没啥问题啊。
看,用得挺好的,妥妥的啊。
我们再来看另外一种情况。
xx,报错了,咋回事?在项目中,由于我们的疏忽,有时候定义的变量忘记写var关键字都是时常有的事,在一个代码量很庞大的应用中,定位这样的一个bug肯定需要花费不少时间,而且很容易让人抓狂。
上面那种情况将一个数组赋值给status并调用push方法为啥不出错,这里就涉及到javascript变量作用域的问题了,因为一个自执行函数就是一个作用域,系统在查找这个变量时是先在这个作用域内进行查找,找不到就往上一层作用域中查找,直到作用域的最前端,没有找到就报错提示变量is not defined。这里因为在当前作用域中申明了变量status,所以不会去window环境下去查找status变量,所以是ok的,但是下面这种情况因为没有使用var进行变量的申明,所以status就会成为window下的变量,而status又是window下的一个固有属性,取值的时候只能是string类型,从而没有push方法,最终报错。
所以,为了不给自己制造那么多麻烦,在定义变量时应该尽量避免使用javascript中的关键字、保留字和window下的固有属性进行命名,这些都是坑,实际项目中应该多注意避免。
从以上分析中,我们看到全局的status可以设置,但是读取的时候却调用了toSting方法返回了字符串,这里我们可以利用es5提供的Object.defineProperty来模拟一下这种行为。代码如下:
var a = {}; Object.defineProperty(a, 'm', (function () { var _a = 'xx'; return { get : function () { return _a.toString(); }, set : function (v) { _a = v; } }; })()); |
利用Object.defineProperty方法,可以对一个变量或者属性进行监控,当直接赋值给变量的时候就会调用set方法,当直接读取变量的时候就会将调用tostring方法将变量转化为字符串。
我们看到我们模拟的行为和status默认的行为一模一样。
一年前遇到的bug今天才豁然开朗,这让我意识到针对任何一个小的bug都不应该放过,而要报着打破沙锅问到底的态度去探究,这样才可以看到别样的风景以及让自己更加专业。