JavaScript需要避免的问题总结
2016-11-30 15:13
232 查看
JavaScript需要避免的问题总结
最近看了Douglas Crockford的《JavaScript 语言精粹》,对于JavaScript有了新的了解,本文主要总结一下JavaScript语言特性引起的一些常见问题,以及避免方法。JavaScript需要避免的问题总结
检索
枚举
减少全局污染
1.检索
JavaScript检索对象包含值的方法有两种,一种是”[]”,另一种是”.”,一般两种方式都可用。但在检索的字符串是一个非法JavaScript标示符或者为保留字时,”.”是不可用的,只能使用name[“first-name”](在对象字面量定义时也是如此,由于“first-name”是非法标示符,所以定义时必须用引号包含——“first-name:”“Joe”)。
书中建议使用”.”方法检索,也就是name.first_name。所以就需要编码时注意标示符的合法性,以及不要和保留字冲突。
另外一个更重要的问题是,检索一个不存在的成员属性时,将返回undefined,而从undefined中取值会导致TypeError异常,例:age不为name对象的属性,name.age为undefined,name.age.child则会抛出异常。解决方法为 设置默认值var age = name.age || “unknown”, 也可以通过“&&”运算避免错误: name.age&&name.age.child。
2.枚举
for in 语句可以遍历一个对象中所有属性名,但同时还包括函数和原型中的属性。解决方法一就是,过滤掉不需要的属性:var name; for(name in names){ if(names.hasOwnProperty(name) && typeof names[name] !=='function'){ document.writeln(name + ' : ' + names[name]); } }
其中hasOwnProperty方法检测对象是否有指定属性,且不检查原型链;若属性值为函数,typeof返回’function’类型。
另一种解决方法就是,完全避免使用for in语句,使用常规for语句。
因为for in语句除了上述问题以外,枚举的属性名出现的顺序是不确定的,若要使顺序确定,则可以创建一个数组,以正确的顺序包含属性名,然后用for语句遍历:
var i; var properties =[ 'first_name', 'middle_name', 'last_name' ]; for(i=0; i<properties.length; i+=1){ document.writeln(properties[i] + ':' + names[properties[i]]); }
这样既保证了顺序,又直接确定了需要的属性。(但这种方法需要自己创建数组,且需要自己确定属性名,虽然书中推荐这种方法,但还要看具体情况)
3.减少全局污染
Douglas Crockford在书中指出,JavaScript对全局变量的依赖是所有糟糕特性中最糟糕的一个,因为全局变量可以被程序的任何部分在任意时间修改,降低了程序的可靠性,且全局变量名称会和子程序变量名称产生冲突,导致程序无法运行且难以调试。共有3种方式定义全局变量:
在任何函数之外声明: var foo = value;
直接给全局对象添加属性: window.foo = value; (window为web浏览器的全局对象)
直接使用未经声明的变量: foo = value; (即隐式的全局变量)
减少全局污染的方法一:最小化使用全局变量 ,一个应用只创建一个唯一全局变量
var MYAPP = {}; MYAPP.name = { ... }; MYAPP.method={ ... };
另一种减少全局污染的方法是,使用函数和“闭包”构建模块来进行信息隐藏:
“内部函数可以访问它们外部函数的参数和变量(除了this和arguments),内部函数拥有比它的外部函数更长的生命周期,内部函数访问外部函数的实际变量而无需复制。”
所谓“闭包”即是函数可以访问它被创建时所处的上下文环境(可以简单理解为内部函数可以访问外部函数定义的变量)。
模块即利用函数作用域和“闭包”构建的只提供接口,隐藏其中状态信息的函数或对象。
这里举书中的一个例子:
var serial_maker = function(){ var prefix = ''; var seq = 0; return { set_prefix: function(p){ prefix=String(p); }, set_seq: function(s){ seq = s; }, gensym: function(){ var result = prefix + seq; seq +=1; return result; } }; }; var seqer = serial_maker(); seqer.set_prefix('Q'); seqer.set_seq(1000); var unique = seqer.gensym();
seqer只提供接口方法set_prefix、set_seq和gensym,由于函数作用域,私有变量对其他程序是不可见的,只能通过这些方法改变prefix 和seq的值。
也可以构造一个对象:
var myObj = (function() { var value=0; return { increment: function(inc){ value += typeof inc === 'number'?inc:1; }, getValue: function(){ return value; } }; }()); myObj.increment(1); myObj.getValue();
注意“()”,以上返回的是函数运行的结果,即包含两个方法的对象。
模块模式的一般形式为第一种方式:定义了私有变量和函数的函数;利用闭包创建访问私有变量和函数的接口函数;最后返回这个函数,或者放到可以访问的地方。
利用模块模式可以摒弃全局变量的使用。
可参考另外一篇文章JavaScript的几点编码规范提高代码质量
相关文章推荐
- javascript处理HTML的Encode(转码)和Decode(解码)总结,避免js脚本注入问题
- 业务需要,得到了两段正则表达式的代码,JAVASCRIPT的(关于车牌号码的校验问题)。
- javascript弹出窗口问题总结
- 总结JavaScript在IE9之前版本中内存泄露问题
- Javascript给隐藏控件赋值之后,ASP.NET不能正确取值问题总结
- 一些Javascript的IE和Firefox(火狐)兼容性的问题总结及常用例子
- JavaScript Tip/Trick: 动态创建Table时,在IE中需要注意的一个问题
- 几个需要总结的问题
- Firefox - 附加软件 - Firebug - 其他问题 - 设置Javascript.options.strict为False避免Firebug出错
- javascript弹出窗口问题总结
- javascript 避免闭包引发的问题
- javascript弹出窗口问题总结
- javascript弹出窗口问题总结
- javascript弹出窗口问题总结
- JavaScript Tip/Trick: 动态创建Table时,在IE中需要注意的一个问题
- javascript弹出窗口问题总结
- javascript弹出窗口问题总结
- javascript弹出窗口问题总结
- javascript弹出窗口问题总结
- Firefox中Javascript使用event对象需要注意的问题