一次关于使用status作为变量引发的bug及思考
这个bug出现在一年前,当时自己大学还没毕业,刚刚进入一家公司实习。那个时候还没有用seajs或者requirejs那样的模块化管理的库,也没有用一个自执行的函数将要执行的代码包裹起来,于是bug就在这样的一个场景下诞生了。当时自己定位了比较久,也不知道status是window下的一个属性,所以请了高手帮忙定位,高手也是定位了半天才定位出来,只是凑巧将status换了一个名字就正常了,后来我问高手原因,他当时也答不出来,后来就一直没管它了,也忘记了。就在前几天,群里有人在讨论一些bug以及要注意的一些坑,我突然想起了一年前自己遇到过的坑,于是提了出来,在各位高手的讨论下终于搞懂了这个bug出现的原因以及原理,于是记录下,方便那些跟我一样做开发的同学能够绕过这些坑,少走弯路。
1.场景再现(为了方便最简化代码,当时的情景不像下面这么直白的提示错误):

咦,为什么这里status是一个数组,为什么会提示它没有push函数呢,这到底是为什么呢?这个bug对于当时初出茅庐的我来说简直就是一个大挑战,那个时候对调试还不熟,看到bug那个小心脏顿时就有点受不了了,紧张啊,抓狂啊随之而来。因为当时代码量比较多,所以当时不能一下子定位到这里的问题。
2.讨论

我们看到就因为变量名不同,却一个出错一个正常,难道不能将一个数组赋值给status吗?

我们看到将一个数组赋值给status是完全没有问题的,它是数组类型。既然是数组为什么就没有push方法呢?这个时候我们不防打印下status的类型

我们看到我们将一个数组赋值给status,按理说应该是object类型,可是这里却是string类型,string类型没有push方法,这时我们对于为什么报错就没有那么疑惑了。按这样理解的话,就是在给status赋值时确实是将一个数组赋给了它,但是就是在读取status时浏览器强制将status转化成了字符串。我们不防在chrome控制台看看。

看来我们的猜测是对的,赋值成功,在取值的时候将status强制转化为了字符串,那要是将一个对象赋值给status在读取status的时候是不是也会将status转化为json格式的字符串呢?

我们看到,浏览器并没有按我们的预期将它转化为一个json格式的字符串,而是转化为[object Object]这样的东东,这不是我们经常用来判断变量的类型吗?一般我们会调用Object.prototype.toString.call(变量)来查看变量类型,因为使用typeof太不靠谱。于是我们猜到在将status转化为字符串的时候是调用了toString方法。
难道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都不应该放过,而要报着打破沙锅问到底的态度去探究,这样才可以看到别样的风景以及让自己更加专业。
一次关于使用status作为变量引发的bug及思考的更多相关文章
- unity3d之public变量引发错误
public变量引发错误 在vs ide中怎么更改也无效 后来发现public里面的值一直不改变,手动改之.
- shell脚本中定义路径变量出现的BUG
=========================================================================== if 语句中的定义路径变量 引发命令的PATH路 ...
- QByteArray引发的bug
QByteArray引发的bug 在接收UDP数据的函数里,有如下代码片段 if(0x10 == data.size() && 0xCA == (unsigned char)data. ...
- Spring 循环引用(一)一个循环依赖引发的 BUG
Spring 循环引用(一)一个循环依赖引发的 BUG Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 循环 ...
- 安卓微信overflow-x overflow-y引发的bug
今天xgo文章图片页上线用微信扫页面发现一个bug,页面可以双击放大缩小. 找了半天原因,发现是图片描述设置了overflow-y引发的bug. 建议在微信场景里满屏显示不能滚动的页面里慎用overf ...
- [Linux][C][gcc][tips] 在头文件中定义变量引发的讨论
概述 本人的原创文章,最先发表在github-Dramalife-note中.转载请注明出处. Define variable(s) in header file referenced by mult ...
- 记录一个i变量引发的事故
概述 近期开发中遇到一个特别的问题,觉得很有必要与你下来.就是由于在开发中一个很小的疏忽,导致了很大的问题,是什么呢? 现象 我的程序突然引发了v8内部的错误,提示都是c++的,如下.程序一启动就直接 ...
- [BUG]自己的bug自己解,记一次在变量使用过程引发的bug
[实现的功能要求]在短信编辑界面,将所有的emoji表情全部插入到编辑区域,其中表情共有5页,每遍历完一页时需要自动翻页重新获取表情并插入,在第5页中只有10个表情 下面先看看这段代码,大家能否看出有 ...
- windows环境变量引发的血案
最近重装了系统,决心使用Anaconda来管理python包和虚拟环境.在完成一系列配置后,运行程序,发现老是报错 D:\Anaconda3\envs\jobnote>python E:\wor ...
随机推荐
- Bzoj1823 [JSOI2010]满汉全席
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1640 Solved: 798 Description 满汉全席是中国最丰盛的宴客菜肴,有许多种不同的 ...
- crawler: 爬虫的基本结构
目前我所知道的爬虫在获取页面信息上,分为静态爬虫和动态爬虫:静态爬虫主要用于获取静态页面,获取速度一般也比较快:但是现在很多网站的页面都是采用动态页面,当我们用爬虫去获取信息的时候,页面的信息可能还没 ...
- Newtonsoft.Json动态过滤属性
Newtonsoft.Json动态过滤属性 接口写的多了,会发现很多的问题.同一个dto,不同的action返回的字段个数不一样.往往开发人员因为懒或者各种原因一股脑的全返回,会浪费很多流量且用户体验 ...
- TypeScript Basic Types(基本类型)
在学习TypeScript之前,我们需要先知道怎么才能让TypeScript写的东西正确的运行起来.有两种方式:使用Visual studio 和使用 NodeJs. 这里我选择的是NodeJs来编译 ...
- 为什么要用Markdown写东西
为什么要用Markdown 不用费心去调格式了,比方说题目加粗什么的,删除线什么的,代码也只要四个空格就好了~ 学起来很简单,几乎没什么学习成本,而收益却很大 这几乎快让我我想从cnblog转到简书了 ...
- 画虚线 iOS
整理了一个方法,可以直接绘制虚线,下面直接上代码.参数说明已经给出,可直接copy使用 /** ** lineView: 需要绘制成虚线的view ** lineLength: 虚线的宽度 ** li ...
- 你所知道好玩有趣的 iOS URL schemes 有哪些?
QQ的url是 mqq:// 微信是weixin:// 淘宝taobao:// 点评dianping:// dianping://search 微博 sinaweibo:// 名片全能王camcard ...
- 【Beta版本】冲刺-Day2
队伍:606notconnected 会议时间:12月10日 目录 一.行与思 二.站立式会议图片 三.燃尽图 四.代码Check-in 一.行与思 张斯巍(433) 今日进展:对登录界面做了相应的修 ...
- 各种编码UNICODE、UTF-8、ASCII学习笔记
本文转自csdn博客:http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html ,感谢作者的分享 作者: 阮一峰 日期: ...
- 将文件路径以"\"隔开
将文件路径以"\"隔开,这货搞了我一小时...C++返回一维数组,字符串数组还是要再看看 ]) { ; //string s_array[30]; //局部变量,如果使用retur ...