`

如何书写高质量js代码

 
阅读更多
>>>>> 避免全局变量,因为全局变量容易发生名称上的冲突,可维护性不好。
	1,使用命名空间
	2,使用闭包
	3,在函数内部使用var声明
function sum(x,y){
     result = x + y;
     return result;
}
alert(window.result); 所有全局变量都是window的一个属性
如果调用sum函数,就会自动多一个result的全局变量,在javascript中,所有未声明的变量都会成为全局对象的一个属性

使用链式方法声明变量
function foo(){
     var a=b=0;
     ....
}
 虽然a是局部变量,但这样b就变成全局变量,这是因为,
 b = 0这个表达式先执行,执行的时候b并没有被声明,所以b就成为了全局变量,然后返回这个表达式的值0,给声明了的变量a
 如果你已经声明了var a,b这样是可以的。
 
 另外一个避免使用全局变量的原因是考虑到程序的可移植性。
 如果你想让你的代码在不同的环境中都可以工作,那么使用全局变量就很可能会与新的系统中的全局变量冲突(或许在之前的系统中没有问题)。
 
使用var声明的全局变量和没有使用var生成的全局变量还有一个区别在于删除:

使用var声明创建的全局变量不能被删除

没有使用var声明的全局变量可以被删除

这说明没有使用var声明生成的全局变量不是真正的变量,他们只是全局对象的属性。属性可以通过delete删除,但是变量不行

在你的代码的顶部只是用一个var关键字,会有以下的好处:
 对于所有需要的变量,在一个地方就可以全部看到 
 避免使用一个未定义的变量 
 帮助你记忆声明的变量,减少全局变量 
 更精简的代码 
 书写很简单
通过一个var和逗号来声明多个变量。
在声明的时候给变量赋默认值也是不错的做法,可以避免一些逻辑错误,提高代码的可读性。而后你阅读的代码的时候也可以根据变量的默认值来方便的猜测变量的用途。

JavaScript允许你在函数内部有多个var语句,但是却都表现的如同在函数的顶部声明一样。
这个特性在你使用一个变量然后在后面又声明了这个变量时会导致一些奇怪的逻辑问题。
对于JavaScript来说,只要变量在同一个作用域,那么就认为是声明了的,就算是在var语句之前使用也一样。看看这个例子:

myname = "global"; // global variable
function func() {
    alert(myname); // "undefined"
    var myname = "local";
    alert(myname); // "local"
}
func();

在这个例子中,或许你期望第一次会弹出global,第二次弹出local。
因为第一次的时候没有还没有使用var声明myname,这是应该是全局变量的myname,第二次声明了,然后alert之后应该是local的值。
而事实上不是这样的,只要你在函数中出现了var myname,那么js就认为你在这个函数中声明了这个变量,
但是在读取这个变量的值的时候,因为var语句还没有执行,所以是undefined,很奇怪的逻辑吧。上面的代码相当于:

myname = "global"; // global variable
function func() {
   var myname; // same as -> var myname = undefined;
   alert(myname); // "undefined"
   myname = "local";
   alert(myname); // "local"
}
func();

在代码的解析中,分两个步骤,第一步先处理变量函数的声明,
这一步处理整个代码的上下文。第二步就是代码的运行时,创建函数表达式以及未定义的变量。

>>>>>  for循环

for (var i = 0; i < myarray.length; i++) {
   // do something with myarray[i]
}

这样每次迭代都会计算数组的长度。尤其在这个参数不是一个数组而是一组HTML元素的时候会降低你的程序的性能。

for (var i = 0, max = myarray.length; i < max; i++) {
   // do something with myarray[i]
}

先保留长度,不用每次都计算。
在查找HTML元素集合的时候,缓存参数长度可以带来可观的性能提升,Safari下面提高两倍的速度,在IE7下面提高190倍的速度。
需要注意的是,当你需要操作修改DOM元素的数量的时候,你肯定希望这个值是随时更新的而不是一个常量。
使用下面的单一var模式,你也可以把var提到循环之外:
function looper() {
   var i = 0,
        max,
        myarray = [];
   // ...
   for (i = 0, max = myarray.length; i < max; i++) {
      // do something with myarray[i]
   }
}
这个模式可以增强整个代码的连续性,但是不好的一点是当你重构代码的时候复制粘贴就没那么容易了。
例如:如果你想在其他函数中也使用这个循环,那你需要确定在新的函数中处理好了i和max(或许还需要删掉这个)。

这个函数还有两个点可以优化的:

可以少一个变量(不需要max) 
递减到0,一个数字与0比较比这个数字与另外一个数字比较更快 
所以就可以写为:
var i, myarray = [];
for (i = myarray.length; i--;) {
   // do something with myarray[i]
}
针对第二点:

var myarray = [],
    i = myarray.length;
while (i--) {
   // do something with myarray[i]
}   
  :) 哟西。
  
  
>>>>>>> for in 循环 for-in循环用来迭代非数组的对象。使用for-in循环通常也成为枚举。

从技术上来说,你也可以用for-in来循环数组,因为数组也是对象,但是不推荐。如果数组有一些自定义的扩展函数,
那么就会出错。另外,对象属性的顺序在for-in循环中也是不确定的。所以最好还是用普通的循环来循环数组用for-in来循环对象

在循环对象的过程中,使用hasOwnProperty()方法来检验是对象本身的属性还是原型链上的属性很重要。
看看下面的这个例子。

// the object
var man = {
   hands: 2,
   legs: 2,
   heads: 1
}; 
 
// somewhere else in the code
// a method was added to all objects
if (typeof Object.prototype.clone === "undefined") {
   Object.prototype.clone = function () {};
}

在这个例子中,我们有一个简单的称作man的对象字面量。在其他man定义之前或之后的地方,对象原型有一个很有用的clone()方法。
因为原型链的原因,所有的对象都自动获得了这个方法。
为了在枚举man对象的时候出现clone方法,你需要使用hasOwnProperty方法来区别。如果没有区别来自原型链的方法,那么就会有一些意想不到的事情发生:

// 1.
// for-in loop
for (var i in man) {
   if (man.hasOwnProperty(i)) { // filter
      console.log(i, ":", man[i]);
   }
}
/* result in the console
hands : 2
legs : 2
heads : 1
*/
// 2.
// antipattern:
// for-in loop without checking hasOwnProperty()
for (var i in man) {
   console.log(i, ":", man[i]);
}
/*
result in the console
hands : 2
legs : 2
heads : 1
clone: function()
*/

另外一种使用方法如下:
for (var i in man) {
   if (Object.prototype.hasOwnProperty.call(man, i)) { // filter
      console.log(i, ":", man[i]);
   }
}

这样写的好处是可以防止man重新定义了hasOwnProperty方法导致的冲突。如果不想写这么长的一串,你也可以这样:

 var i, hasOwn = Object.prototype.hasOwnProperty;
for (i in man) {
    if (hasOwn.call(man, i)) { // filter
        console.log(i, ":", man[i]);
    }
}

严格意义上讲,不适用hasOwnProperty也不是什么错误。根据任务的难度和你对代码的自信程度,你也可以不用这个直接循环。
但是当你不确定的时候,最好还是使用这个方法检测一下。

另外一种格式上的改变(不会通过jsLint的检查),去掉for的大括号,然后把if放在同一行。这样做的好处可以让循环体更加突出,缩进也就少一些:
// Warning: doesn't pass JSLint
var i, hasOwn = Object.prototype.hasOwnProperty;
for (i in man) if (hasOwn.call(man, i)) { // filter
    console.log(i, ":", man[i]);
}

>>>>>>> 不要扩展内建的原型

扩展原型的构造函数,可以提供一些很强大的功能,但是有时候他太强大了。

有时候你会去扩展Object(),Array(),Fucntion()的原型方法,这样会导致可维护性的问题,因为这会让你的代码的移植性变差。其他的开发人员使用你的代码的时候,可能只需要原生的方法,并不需要额外的功能。

另外,你添加进去的方法,如果在循环的时候没有使用hasOwnProperty方法就会被遍历出来,这会让人很迷惑。

所以,最好还是不要扩展基本的对象。除非是下面的情况:

你确定在将来根据ECMAScript规范,浏览器会添加相应的原型方法,那么是可以的,你只不过是提前实现了这个功能。 
你确定的你要实现的方法不存在–或许有时候在代码的其他的地方实现了,或者有的浏览器支持,这都是不行的。 
有非常清晰的文档,并且与团队成员沟通过 
如果在这些情况之下,那么你就可以添加,最好是下面这种形式:

if (typeof Object.protoype.myMethod !== "function") { 先判断是否存在
   Object.protoype.myMethod = function () {
      // implementation...
   };
}

>>>>>>>>>>>>>>> switch模式
按照下面的风格写switch的话,可以提高你的代码可读性和健壮性:

var inspect_me = 0,
    result = '';
switch (inspect_me) {
case 0:
   result = "zero";
   break;
case 1:
   result = "one";
   break;
default:
   result = "unknown";
}

需要注意下面几个方面:

将case和switch对齐。 
case的内容缩进 
每一个case之后都有一个清晰的break 
避免顺序往下执行case,非要如此的话,文档一定要写清楚 
最后使用default,保证在没有命中case的情况下也有反馈 


>>>>>>>>>>>>>>>>>>避免隐藏的类型转换

Javascript在你比较两个变量的时候会进行类型的转换,这就是为什么 false == 0或者”" == 0会返回true。

为了避免这种隐藏的类型转换带来的迷惑,最好使用===或者!==操作符来比较:

var zero = 0;
if (zero === false) {
   // not executing because zero is 0, not false
} 
 
// antipattern
if (zero == false) {
   // this block is executed...
}

>>>>>>>>>>>>>>>>>>>>>避免使用eval()
如果你在你的代码中使用eval(),那么要记住”eval() is evil”。这个方法会将传入的字符串当做js代码来执行。
如果代码是在运行前就确定的,那么没有必要使用eval()。如果代码是在运行时动态确定的,那么也有其他更安全的办法。例如使用方括号形式访问元素的属性:

// antipattern
var property = "name";
alert(eval("obj." + property));  
 
// preferred
var property = "name";
alert(obj[property]);

使用eval()还有安全问题,比如你运行网络上的一段代码,而这段代码又被别人篡改了。
在处理Ajax请求返回的JSON数据的时候,最好还是使用浏览器内建的处理方法,如果对于低端的浏览器不支持的,可以从JSON.org上下载对应的处理库。


另外还要记住使用setTimeout、setInterval以及Function的构造函数的是,传入的字符串的参数,js的处理方法跟eval()类似,所以也要注意。
因为,js会把你传入的字符串解析执行:
// no good 
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);  
 
// good 
setTimeout(myFunc, 1000);
setTimeout(function () {
   myFunc(1, 2, 3);
}, 1000);

使用Function的构造函数,跟eval()差不多,也要注意。这是个非常有用的功能,但是常常被错用。如果你必须使用eval(),
那么可以考虑new一个Function来替代。另外的一个好处就是,使用Function的构造函数,
函数的作用域在本方法内,这样你使用var声明的变量就不会变成全局的。
另外一个防止eval()生成全局变量的办法就是使用匿名函数
看看下面这个例子,只有un变量最终是全局的:

console.log(typeof un); // "undefined"
console.log(typeof deux); // "undefined"
console.log(typeof trois); // "undefined"  
 
var jsstring = "var un = 1; console.log(un);";
eval(jsstring); // logs "1"  
 
jsstring = "var deux = 2; console.log(deux);";
new Function(jsstring)(); // logs "2"  
 
 jsstring = "var trois = 3; console.log(trois);";
 (function () {
    eval(jsstring);
 }()); // logs "3"  
 
 console.log(typeof un); // number
 console.log(typeof deux); // undefined
 console.log(typeof trois); // undefined
 
 new Function 一般是这么用的, var a = new Function("a","alert(a)");
一般前面几个是参数,最后一个是函数体。要注意的是函数体是必选项,参数是可选项。一般用在动态定义函数体。

eval()和Function构造函数的另一个区别就是eval()会影响到作用域,而Function则相当于一个沙盒。例如:
 
 (function () {
   var local = 1;
   eval("local = 3; console.log(local)"); // logs 3
   console.log(local); // logs 3
}());  
 
(function () {
   var local = 1;
   Function("console.log(typeof local);")(); // logs undefined
 }());

 

分享到:
评论

相关推荐

    如何书写高质量的jQuery代码

    如何书写高质量的jQuery代码想必大家对于jQuery这个最流行的javascript类库都不陌生,而且只要是前端开发人员肯定或多或少的使用或者接触过,在今天的这篇文章中,我们将介绍一些书写高质量jQuery代码的原则,我们不...

    代码书写器SciLexer

    **代码书写器SciLexer**是一款专门用于编写C/C++源代码的编辑器,它以其简洁、美观和功能强大的特点受到程序员的青睐。SciLexer是该编辑器的核心组件,它提供了丰富的语法高亮和代码提示功能,极大地提高了代码的...

    12条写出高质量JS代码的方法

    书写出高质量的JS代码不仅让程序员看着舒服,更加能够提高程序的运行速度,以下就是软件开发网的小编整理方法: 一、如何书写可维护性的代码 当出现bug的时候如果你能立马修复它是最好的,此时解决问题的四路在你脑...

    如何书写高质量jQuery代码(使用jquery性能问题)

    1.正确引用jQuery 1.尽量在body结束前才引入jQuery,而不是在head中。...前引入script文件的话,就不用写document.ready了,因为这时执行js代码时DOM已经加载完毕了。 &lt;body&gt; [removed]&lt;/scri

    PHPCodeSniffer一个检测PHPCSS和JS代码标准冲突的库

    **PHP Code Sniffer (PCS)** 是一个非常重要的工具,尤其对于PHP、CSS和JavaScript的开发者而言。...通过定期检查和修复代码风格问题,开发者能够编写出更易于理解和维护的代码,从而提升整体项目的质量和稳定性。

    HTML5 SVG汉字书写笔画特效.zip

    SVG是一种基于XML的矢量图形格式,它支持动态内容和交互性,使得在网页上创建高质量、可缩放的图形成为可能。在HTML5 SVG汉字书写笔画特效中,每个汉字被分解为多个基本笔画,这些笔画以SVG路径数据的形式存储,然后...

    ArtDialog Vista风格高兼容度的javascript对话框组件 ArtDialog 仿Vista风格的javascript对话框组件,具有超高的兼容性,对IE、火狐、Google浏览器兼容都不错,而且设计精美,弹出框的功能也很多:比如弹出图片、弹出动画、右下角消息、询问框、警告、弹出菜单、调用外部页面等,代码书写规范,也可作为学习JavaScript的参考范例。

    通过研究其源代码,开发者可以了解到如何编写高质量、高性能的JavaScript代码,以及如何构建可复用的组件。 总的来说,ArtDialog是一个功能强大、兼容性好、设计优雅的JavaScript对话框组件。无论是专业开发者还是...

    代码规范

    提及"源码"和"工具"标签,源码分析是理解软件工作原理的关键,通过阅读高质量的源码,开发者可以学习到优秀的编程技巧和设计模式。同时,源码审查也是保证代码规范的一种手段,团队成员可以互相审查代码,指出不符合...

    腾讯 Alloyteam 代码规范.pdf

    腾讯Alloyteam代码规范是一份由腾讯Alloyteam团队制定和维护的代码编写标准,旨在提供...通过这些规范,开发者可以编写出更加高质量、更加标准化的代码,这不仅有助于团队内部的协作,也有利于整个开发社区的健康发展。

    seven初稿源代码

    1. **源代码**:源代码是程序员用高级编程语言(如Java, Python, C++, JavaScript等)书写的文本文件,它们是程序的原始形式,包含了一系列人类可读的指令。源代码对于软件开发至关重要,因为它允许开发者理解和修改...

    VUE-CLI项目代码规范.docx

    VUE-CLI 项目代码规范 在本文档中,我们将讨论 VUE-CLI 项目代码规范,涵盖命名规则、CSS 书写规范、JS 书写规范和 .vue 文件书写...这些规范旨在帮助开发者编写高质量的 Vue.js 代码,提高代码的可维护性和可读性。

    百度前端代码规范.pdf

    Javascript编码规范是整个文档的核心部分,它详细描述了如何编写高质量的JavaScript代码。规范建议使用无BOM的UTF-8编码格式,以避免在不同平台间交换文件时可能出现的兼容性问题。此外,规范还强制要求文件以空行...

    JS技巧大全 javascript

    - 学习TypeScript,为JavaScript添加静态类型检查,提高代码质量。 15. **Web API** - 了解并掌握`fetch`、`XMLHttpRequest`等API进行网络请求。 - 使用`Web Storage`(localStorage 和 sessionStorage)进行...

    前端代码规范-js,html,vue,css,ts

    3. **优化基础代码规范**:利用现有工具辅助开发者在日常工作中遵循基本的编码准则,从而提高代码质量和可维护性。 #### 实施方案 1. **利用规范工具**: - 对于新项目或小型项目,采用构建工具中的 linting 工具...

    前端代码规范.pdf

    以上规范旨在提升前端项目的专业性和质量,通过遵循这些规则,开发者可以构建出更高质量、易于维护的前端应用。在实际工作中,团队应根据自身需求和项目特点,灵活调整和补充这些规范,以实现最佳的开发效果。

Global site tag (gtag.js) - Google Analytics