这个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及思考的更多相关文章

  1. unity3d之public变量引发错误

    public变量引发错误 在vs ide中怎么更改也无效 后来发现public里面的值一直不改变,手动改之.

  2. shell脚本中定义路径变量出现的BUG

    =========================================================================== if 语句中的定义路径变量 引发命令的PATH路 ...

  3. QByteArray引发的bug

    QByteArray引发的bug 在接收UDP数据的函数里,有如下代码片段 if(0x10 == data.size() && 0xCA == (unsigned char)data. ...

  4. Spring 循环引用(一)一个循环依赖引发的 BUG

    Spring 循环引用(一)一个循环依赖引发的 BUG Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 循环 ...

  5. 安卓微信overflow-x overflow-y引发的bug

    今天xgo文章图片页上线用微信扫页面发现一个bug,页面可以双击放大缩小. 找了半天原因,发现是图片描述设置了overflow-y引发的bug. 建议在微信场景里满屏显示不能滚动的页面里慎用overf ...

  6. [Linux][C][gcc][tips] 在头文件中定义变量引发的讨论

    概述 本人的原创文章,最先发表在github-Dramalife-note中.转载请注明出处. Define variable(s) in header file referenced by mult ...

  7. 记录一个i变量引发的事故

    概述 近期开发中遇到一个特别的问题,觉得很有必要与你下来.就是由于在开发中一个很小的疏忽,导致了很大的问题,是什么呢? 现象 我的程序突然引发了v8内部的错误,提示都是c++的,如下.程序一启动就直接 ...

  8. [BUG]自己的bug自己解,记一次在变量使用过程引发的bug

    [实现的功能要求]在短信编辑界面,将所有的emoji表情全部插入到编辑区域,其中表情共有5页,每遍历完一页时需要自动翻页重新获取表情并插入,在第5页中只有10个表情 下面先看看这段代码,大家能否看出有 ...

  9. windows环境变量引发的血案

    最近重装了系统,决心使用Anaconda来管理python包和虚拟环境.在完成一系列配置后,运行程序,发现老是报错 D:\Anaconda3\envs\jobnote>python E:\wor ...

随机推荐

  1. Apache日志配置参数详细说明

    Apache日志按时间分段记录 在apache的配置文件httpd.conf中找到ErrorLog logs/error_log及CustomLog logs/access_log common Li ...

  2. VMP虚拟机加壳的原理学习

    好久没有到博客写文章了,9月份开学有点忙,参加了一个上海的一个CHINA SIG信息比赛,前几天又无锡南京来回跑了几趟,签了阿里巴巴的安全工程师,准备11月以后过去实习,这之前就好好待在学校学习了. ...

  3. Ubuntu修改mysql默认编码的方法

    ubuntu使用apt-get安装mysql后,server的默认编码是latin1,下面把server的编码修改成utf8. 编码相关信息: 1 2 3 4 5 6 7 8 9 10 11 12 1 ...

  4. angularjs $q、$http 处理多个异步请求

    angularjs $q.$http 处理多个异步请求 在实际业务中经常需要等待几个请求完成后再进行下一步操作.但angularjs中$http不支持同步的请求. 解决方法一: $http.get(' ...

  5. zabbix使用介绍

    zabbix自定义监控项 1.创建主机组,可以根据redis.mysql.web等创建对于的主机组 2.创建主机 3.创建Screens 4.自定义监控项 zabbix_agentd.conf配置文件 ...

  6. ionic 发送请求返回一直都是404

    在web端调试一直都没有问题,生成app之后发现所有的请求返回的都是404, 断掉wifi和4G之后发送的也是404 原因是未引入插件 解决方法是在根目录下执行一下命令 cordova plugin ...

  7. HBase与MongDB等NoSQL数据库对照

    HBase概念学习(十)HBase与MongDB等NoSQL数据库对照 转载请注明出处: jiq•钦's technical Blog - 季义钦 一.开篇 淘宝之前使用的存储层架构一直是MySQL数 ...

  8. 【原】js检测移动端横竖屏

    摘要:上周做了一个小项目,但是要放到我们的app上,然而需要横竖屏使用不同的样式.横屏一套,竖屏一套.调用了手机APP那里的api,可是他们那里ios和安卓返回的不一样. 各种头疼.于是用了css3的 ...

  9. DataView

    表示用于排序.筛选.搜索.编辑和导航的 DataTable 的可绑定数据的自定义视图. DataView的功能类似于数据库的视图,他是数据源DataTable的封装对象,可以对数据源进行排序.搜索.过 ...

  10. xpath php

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> < ...