初涉JavaScript模式 (2) : 基本技巧

时间:2021-07-08 22:54:32

尽量少用全局变量

大量使用全局变量会导致的后果

全局变量创建以后会在整个JavaScript应用和Web页面*享。所有的全局变量都存在于一个全局命名空间内,很容易发生冲突

不知不觉创建了全局变量

其原因在于JavaScript的两个特性,第一个是JavaScript可直接使用变量而无需声明,第二个是JavaScript的暗示全局变量的概念,即任何变量如果未经声明,就为全局对象所有

为了避免我们无意间创建了全局变量 我们可以使用var声明变量

另一种创建暗示全局变量的反模式是带有var声明的链式赋值。

产生上面结果的原因是 JavaScript的从右到左的操作符优先级 它的执行顺序是这样的

```javascript
var a = (b = 0); ```

解决方案也很简单 就是对链式赋值的所有变量都进行赋值,如下代码所示:

```javascript

  function demo(){
var a,b;
a = b = 0;
} ```

另一个避免全局变量大量使用的原因在于代码移植,你的代码在当前环境(主机)运行是没有问题的,但换个环境,全局变量可能会和存在于其他环境的变量发生冲突。

全局变量的释放

暗示全局变量和明确定义的全局变量有细微的不同,不同之处在于是否能用delete销毁,代码如下:

以上代码说明暗示全局变量可以通过delete删除,而var定义则不能

访问全局变量

在浏览器下,可通过window属性在代码的任意位置访问到全局变量,但是也可能发生意外(声明了一个名为window的局部变量)。

在其他环境下(如NodeJS),window就不叫window了,NodeJS下整个Runtime时期的全局变量是global,顾用window还不够严谨。

解决方案代码如下:

```javascript

  var global = (function(){
return this;
}()); ```

按这种方式通常都能获取全局对象,因为this在函数内部作为一个函数调用(不是通过构造器创建也不是通过call,apply指定),往往指向全局对象

但是如果你的代码运行在ES5的严格模式下,就不能这样用了,解决代码如下:

变量及函数声明的提升

JavaScript允许在函数的任意地方声明多个变量或函数,无论在哪里声明都等同于在函数顶部声明,这就是所谓的提升

以上代码说明 var v1 被看做是局部变量的声明,所以打印出来的是undefined 这其实还涉及到一个变量对象(Variable Object)的问题,打印的时候他会先在Variable Object中找,如果找不到才会到window中去找,如果发现有了,则直接打印出来

for循环的优化

看到这里,你可能会觉得奇怪,for还有可以优化的地方吗?谈不上优化,就是一些注意点

闲话不多说直接上代码:

```javascript
//经典的for循环
for(var i = 0; i < array.length; i++){
//对array[i]进行操作
}
```

这种模式的问题在于每次循环都要访问数组的length,如果是数组还好,影响不是很大(速度变慢)。但是如果遍历的是DOM集合,我们知道在document下操作DOM是很耗性能的,而如果我们将length用变量保存起来,从而避免了每次循环对DOM的查询,在所有的浏览器中都会大大降低性能的损耗,其中在safari中速度会提高3倍,IE7中会提高170倍之多

还有一个可以改进的是可以通过:

```javascript
var array = [],len = array.length ;
for(len,len--){
//处理array[len]
}
```

这种模式 有2个好处,使用了最少的变量,逐步减至0,因为同0比较 比 同数组的长度比较速度更快

还有一种while的模式,和这个类似,我就不贴代码了(嘿嘿)

不要增加内置对象的原型

以前喜欢写这种代码,被我英明的 “会哥” 提醒了一下,专门去看了下,反模式的典型啊。。。自我检讨下

增加内置构造函数(Object,Array,Function)的原型是很爽的(埋下的坑迟早要填。。),但是这可能会严重影响可维护性,因为这将使你的代码变得更加不可预测,比如你重写了Array的slice方法,而别的工程师不知道,他得不到预期的结果(比全局对象污染更严重),如果一定要写也必须先准确的记录下来,并和团队交流清楚

应该避免的一些小细节

避免使用隐式类型转换

JavaScript 在执行比较语句的时候会进行隐式类型转换,这也是为什么执行 false==0 或 "" == 0 这类比较语句会返回true的原因

为了避免隐式转换造成的混淆不清,最好在使用比较语句的时候使用 === 和!===


避免使用eval()

eval 会将任意字符串当作JavaScript代码来执行(ES5 严格模式下使用eval会报错),eval会执行被修改过的代码(可能被客户端修改),会产生一些安全隐患

eval的替代方案 使用浏览器自带的方法来解析JSON请求 JSON.parse() ,对于不支持parse的可以使用来自JSON.org的类库,还有就是通过setTimeout,setInterval,和function的构造函数来传递参数,在大部分情况下也会导致类似eval的隐患,如下代码所示:

```javascript
//反模式
setTimeout("func()" , 1000);
setTimeout("func(1,2,3)" , 1000);
//推荐的模式
setTimeout(func , 1000);
setTimeout(function(){
func(1,2,3);
} , 1000);
如果传给setTimeout是字符串,JavaScript仍然会去以程序代码的方式去执行传递过来的字符串,如果一定要用eval,可以考虑用new Function()的方式来替代eval,代码如下:
var code = "console.log(5)"
new Function(code)(); //5
```

使用parseInt的第二个参数

通常第二个参数我们都是忽略,但是有时候会发生一些bug,比如如果我传的字符串是以0开头的就会出现错误,他会不确定是8进制还是10进制,所以最好还是加上进制。另外将一个字符串转换成数值有更快的方法,代码如下:

```javascript
+ “08” //8
Number(“08”) //8
```

这些方法比parseInt快很多,parseInt是解析而不是简单的转换,例如输入“08 soso” 除了parseInt 其他的都会返回NaN

运行JSLint

JSLint 可以检查你的代码,提前发现你的代码有哪些不足,写完代码后在JSLint上跑一遍,这是很好的编程模式(BUG伤不起啊)

后记:

第一次写这么长的博客,文中难免有错误之处,如果能指出感激不进

这篇读书笔记,部分加入了自己工作中遇到的需求加以理解,如有不对之处,请联系我,共同进步

初涉JavaScript模式 (2) : 基本技巧的更多相关文章

  1. 初涉JavaScript模式系列 阶段总结及规划

    总结 不知不觉写初涉JavaScript模式系列已经半个月了,没想到把一个个小点进行放大,竟然可以发现这么多东西. 期间生怕对JS的理解不到位而误导各位,读了很多书(个人感觉JS是最难的oo语言),也 ...

  2. 初涉JavaScript模式 &lpar;13&rpar; &colon; 代码复用 【上】

    引子 博客断了一段时间,不是不写,一是没时间,二是觉得自己沉淀不够,经过一段时间的学习和实战,今天来总结下一个老生常谈的东西: 代码复用. 为何复用 JS门槛低,故很多人以为写几个特效就会JS,其实真 ...

  3. 初涉JavaScript模式 &lpar;12&rpar; &colon; 沙箱模式

    引子 上一篇说了模块模式,而对于其中的命名空间模式其实也是有着一些问题,比如每添加一个模块或则深入叠加都会导致长命名,并且对于多个库的不同版本同时运行,一不小心就会污染全局标识,而这两天也发现了JSe ...

  4. 初涉JavaScript模式 &lpar;11&rpar; &colon; 模块模式

    引子 这篇算是对第9篇中内容的发散和补充,当时我只是把模块模式中的一些内容简单的归为函数篇中去,在北川的提醒下,我才发觉这是非常不严谨的,于是我把这些内容拎出来,这就是这篇的由来. 什么是模块模式 在 ...

  5. 初涉JavaScript模式 &lpar;10&rpar; &colon; 函数 【进阶用法】

    写在前面 不知不觉写到第10篇了.这篇写起来很忐忑,终于和高级搭上边了(呵呵),这篇我们 主要 说一下 JS 方法的部分高级用法(我知道的),笔者水平有限,难免有错.废话不多少,进入正文. 初始化 我 ...

  6. 初涉JavaScript模式 &lpar;9&rpar; &colon; 函数 【常用方式】

    回调模式 上一篇,对JavaScript函数进行了大体的介绍,这一篇对一些在工作中经常遇到的情况进行扩展. 在工作中,我们经常遇到很多需求,比如现在有一个需求: 一栋10层的大楼,当我们在坐电梯时,电 ...

  7. 初涉JavaScript模式 &lpar;7&rpar; &colon; 原型模式 【三】

    组合使用构造函数模式和原型模式 上篇,我们提到了原型模式的缺点,就是每个实例不能拥有自己的属性,因为纯原型模式所有的属性都是公开给每个实例的,故我们可以组合使用构造函数模式和原型模式.构造函数用来定义 ...

  8. 初涉JavaScript模式 &lpar;6&rpar; &colon; 原型模式 【二】

    原型与in操作符 有两种方式使用in操作符:单独使用和在for-in循环中使用. 在单独使用时,in操作符会遍历实例公开(可枚举)的属性,如果找到该指定属性则返回true,无论该指定属性是存在与实例中 ...

  9. 初涉JavaScript模式 &lpar;5&rpar; &colon; 原型模式 【一】

    什么是原型模式? 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象.--引自JavaScript设计模式 我们创建的每一个函数都有一个prototype ...

随机推荐

  1. 非常简单的数据,支持excel表格下载功能

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"% ...

  2. 转:如何向妻子解释OOD

    如何向妻子解释OOD 前言 此文译自CodeProject上<How I explained OOD to my wife>一文,该文章在Top Articles上排名第3,读了之后觉得非 ...

  3. Mac SVN 命令行

    Mac自带了SVN命令行,如我的升级到10.10(OSX yosemite)后命令行版本为1.7.10 以下是一些常用命令 1.将文件checkout到本地目录 svn checkout path(p ...

  4. HTTP协议学习---(十二)理解转发与重定向

    解释一 转发是服务器行为,重定向是客户端行为.为什么这样说呢,这就要看两个动作的工作流程: 转发过程:客户浏览器发送http请求---->web服务器接受此请求-->调用内部的一个方法在容 ...

  5. react 年-月-日 时:分:秒

    // 时间let date = new Date();debugger;let seperator1 = "-";let seperator2 = ":";le ...

  6. oracle查看允许的最大连接数和当前连接数等信息

    目前总结的语句,在查看数据的连接情况很有用 ,写完程序一边测试代码一边查看数据库连接的释放情况有助于分析优化出一个健壮的系统程序来. 1.Sql代码1.select count(*) from v$p ...

  7. java学习:AWT组件和事件处理的笔记&lpar;1&rpar;--文本框上的ActionEvent事件

    学习处理事件时,必须很好的掌握事件源,监视器,处理事件的接口    1.事件源        能够产生java认可事件的对象都可称为事件源,也就是说事件源必须是对象    2.监视器        监 ...

  8. Java菜鸟学习笔记--面向对象篇&lpar;十八&rpar;&colon;对象转型&amp&semi;多态

    Polymorphism[多态] 简述: 面向对象多态性指的是:发送消息给某个对象,让该对象自行决定响应何种行为. 通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用 多态的三个前提条件: 多 ...

  9. 使用Homebrew安装MySQL

    安装命令: brew install mysql 安装完成之后,启动mysql: mysql.server start 发现无此命令: command not found 首先,检查是否是安装了.重新 ...

  10. Modelsim独立仿真Vivado Clocking Wizard IP Core

    工欲善其事,必先利其器.在使用Vivado自带的仿真软件仿真的时候,相对于更优秀的仿真工具Modelsim,效率低了很多,为了更高效的开发,我尝试着用Vivado级联Modelsim仿真,但是级联后还 ...