最小全局变量

JavaScript通过函数管理作用域。在函数内部生命的变量只在这个函数内部,别的地方不可用。全局变量是指在函数外或是未声明直接简单使用的。每个Javascipt环境有一个全局对象,当你在任意函数外使用this都可以访问。你创建的每一个全部变量都成了这个全局对象的属性。在浏览器里,方便起见,该全局对象有个附件属性叫做window,此window指向该全局对象本身。

  1. myglobal = "hello"; // 不推荐写法
    console.log(myglobal); // "hello"
    console.log(window.myglobal); // "hello"
    console.log(window["myglobal"]); // "hello"
    console.log(this.myglobal); // "hello"

全局变量问题

尽量少使用全局变量,并且必须使用var声明。

不推荐写法:

  1. function sum(x, y) {
  2. // 不推荐写法: 隐式全局变量
  3. result = x + y;
  4. return result;
  5. }
  1. // 反例,勿使用
  2. function foo() {
  3. var a = b = 0;
  4. // ...
  5. }

推荐写法:

  1. function foo() {
  2. var a, b;
  3. // ... a = b = 0; // 两个均局部变量
  4. }

Var的好处

1.通过var创建的全局变量是不能被删除的。

2.无var创建的隐式的全局变量是能被删除的。

如代码示例:

  1. // 定义三个全局变量
  2. var global_var = 1;
  3. global_novar = 2; // 反面教材
  4. (function () {
  5. global_fromfunc = 3; // 反面教材
  6. }());
  7.  
  8. // 试图删除
  9. delete global_var; // false
  10. delete global_novar; // true
  11. delete global_fromfunc; // true
  12.  
  13. // 测试该删除
  14. typeof global_var; // "number"
  15. typeof global_novar; // "undefined"
  16. typeof global_fromfunc; // "undefined"

访问全局对象

在浏览中,全局对象可以通过window属性在代码的任何位置访问。但是在其他环境中,这个方便的属性可能被叫做其他东西,甚至在程序中不可用。如果你需要在没有硬编码的window标示符下访问全局对象,你可以在任何层级的函数作用域中做如下操作:

  1. var global = (function () {
  2. return this;
  3. }());

这种方法可以随时获得全局对象,因为其在函数中被当做函数调用了(不是通过new操作),this总是指向全局对象。

单Var模式

在函数顶部使用单Var语句是比较有用的一种形式,其好处在于:

1.提供了一个单一的地方去寻找功能所需要的局部变量。

2.防止变量在定义之前使用了逻辑错误。

3.帮助你记住声明的全局变量,因此较少了全局变量。

4.少代码。

  1. function func() {
  2. var a = 1,
  3. b = 2,
  4. sum = a + b,
  5. myobject = {},
  6. i,
  7. j;
  8. // function body...
  9. }

你可以使用一个var语句声明多个变量,并以都好分割。像这种初始化变量同时初始化值的做法很好。这样子可以防止逻辑错误和增加代码的可读性。

预解析:var散布的问题

Javascript中,你可以在函数中的任何位置声明多个var语句,并且他们就好像是在函数的顶部声明一样发挥作用,这种行为叫做hoisting(悬置,置顶解析,预解析)。当你使用了一个变量,然后不久在函数中又重新声明的话,就可能产生逻辑错误。对于Javascript,只要你的变量在同一个作用域中,他都被当做是声明的,即使是他在var声明前使用的时候。

  1. // 反例
  2. myname = "global"; // 全局变量
  3. function func() {
  4. alert(myname); // "undefined"
  5. var myname = "local";
  6. alert(myname); // "local"
  7. }
  8. func();

var是预解析的,只有当实际的走到这里的时候,才会将var后边的常量放进堆栈中。但是var又是制定解析的并且后方替换前方已声明的变量时,所以才会有上边的undefiend。

for循环

针对for循环,要注意,特别是数组性能损失的问题,如:

  1. // 次佳的循环
  2. for (var i = 0; i < myarray.length; i++) {
  3. // 使用myarray[i]做点什么
  4. }

每次循环myarray.length都要向数组遍历一次,这样性能损失时很大的。

  1. for (var i = 0, max = myarray.length; i < max; i++) {
  2. // 使用myarray[i]做点什么
  3. }

这样写最好,获取length时,仅仅获取了一次。并且这样的写法也很好的体现了单var模式。

for-in循环

for-in循环应该用在非数组对象的遍历上,使用for-in进行循环也被称为“枚举”。

从技术上将,你可以使用for-in循环数组(因为JavaScript中数组也是对象),但这是不推荐的。因为如果数组对象已被自定义的功能增强,就可能发生逻辑错误。另外,在for-in中,属性列表的顺序(序列)是不能保证的。所以最好数组使用正常的for循环,对象使用for-in循环。

有个很重要的hasOwnProperty()方法,当遍历对象属性的时候可以过滤掉从原型链上下来的属性。

思考下面一段代码:

  1. // 对象
    var man = {
    hands: 2,
    legs: 2,
    heads: 1
    };
  2.  
  3. // 在代码的某个地方
    // 一个方法添加给了所有对象
    if (typeof Object.prototype.clone === "undefined") {
    Object.prototype.clone = function () {};
    }

在这个例子中,我们有一个使用对象字面量定义的名叫man的对象。在man定义完成后的某个地方,在对象原型上增加了一个很有用的名叫 clone()的方法。此原型链是实时的,这就意味着所有的对象自动可以访问新的方法。为了避免枚举man的时候出现clone()方法,你需要应用hasOwnProperty()方法过滤原型属性。如果不做过滤,会导致clone()函数显示出来,在大多数情况下这是不希望出现的。

  1. // 1.
    // for-in 循环
    for (var i in man) {
    if (man.hasOwnProperty(i)) { // 过滤
    console.log(i, ":", man[i]);
    }
    }
    /* 控制台显示结果
    hands : 2
    legs : 2
    heads : 1
    */
    // 2.
    // 反面例子:
    // for-in loop without checking hasOwnProperty()
    for (var i in man) {
    console.log(i, ":", man[i]);
    }
    /*
    控制台显示结果
    hands : 2
    legs : 2
    heads : 1
    clone: function()
    */

另外一种使用hasOwnProperty()的形式是取消Object.prototype上的方法。像是:

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

其好处在于在man对象重新定义hasOwnProperty情况下避免命名冲突。也避免了长属性查找对象的所有方法,你可以使用局部变量“缓存”它。

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

严格来说,不使用hasOwnProperty()并不是一个错误。根据任务以及你对代码的自信程度,你可以跳过它以提高些许的循环速度。但是当你对当前对象内容(和其原型链)不确定的时候,添加hasOwnProperty()更加保险些。

格式化的变化(通不过JSLint)会直接忽略掉花括号,把if语句放到同一行上。其优点在于循环语句读起来就像一个完整的想法(每个元素都有一个自己的属性”X”,使用”X”干点什么):

  1. // 警告: 通不过JSLint检测
    var i, hasOwn = Object.prototype.hasOwnProperty;
    for (i in man) if (hasOwn.call(man, i)) { // 过滤
    console.log(i, ":", man[i]);
    }

要记住eval()是魔鬼、

此方法接受任意的字符串,并当做JavaScript代码来处理。

  1. // 反面示例
  2. var property = "name";
  3. alert(eval("obj." + property));
  4.  
  5. // 更好的
  6. var property = "name";
  7. alert(obj[property]);

使用eval()也带来了安全隐患,因为被执行的代码(例如从网络来)可能已被篡改。这是个很常见的反面教材,当处理Ajax请求得到的JSON 相应的时候。在这些情况下,最好使用JavaScript内置方法来解析JSON相应,以确保安全和有效。若浏览器不支持JSON.parse(),你可 以使用来自JSON.org的库。

同样重要的是要记住,给setInterval(), setTimeout()和Function()构造函数传递字符串,大部分情况下,与使用eval()是类似的,因此要避免。在幕后,JavaScript仍需要评估和执行你给程序传递的字符串:

  1. // 反面示例
    setTimeout("myFunc()", 1000);
    setTimeout("myFunc(1, 2, 3)", 1000);
  2.  
  3. // 更好的
    setTimeout(myFunc, 1000);
    setTimeout(function () {
    myFunc(1, 2, 3);
    }, 1000);

使用新的Function()构造就类似于eval(),应小心接近。这可能是一个强大的构造,但往往被误用。如果你绝对必须使用eval(),你 可以考虑使用new Function()代替。有一个小的潜在好处,因为在新Function()中作代码评估是在局部函数作用域中运行,所以代码中任何被评估的通过var 定义的变量都不会自动变成全局变量。另一种方法来阻止自动全局变量是封装eval()调用到一个即时函数中。

考虑下面这个例子,这里仅un作为全局变量污染了命名空间。

  1. console.log(typeof un); // "undefined"
    console.log(typeof deux); // "undefined"
    console.log(typeof trois); // "undefined"
  2.  
  3. var jsstring = "var un = 1; console.log(un);";
    eval(jsstring); // logs "1"
  4.  
  5. jsstring = "var deux = 2; console.log(deux);";
    new Function(jsstring)(); // logs "2"
  6.  
  7. jsstring = "var trois = 3; console.log(trois);";
    (function () {
    eval(jsstring);
    }()); // logs "3"
  8.  
  9. console.log(typeof un); // number
    console.log(typeof deux); // "undefined"
    console.log(typeof trois); // "undefined"

另一间eval()和Function构造不同的是eval()可以干扰作用域链,而Function()更安分守己些。不管你在哪里执行 Function(),它只看到全局作用域。所以其能很好的避免本地变量污染。在下面这个例子中,eval()可以访问和修改它外部作用域中的变量,这是 Function做不来的(注意到使用Function和new Function是相同的)。

  1. (function () {
    var local = 1;
    eval("local = 3; console.log(local)"); // logs "3"
    console.log(local); // logs "3"
    }());
  2.  
  3. (function () {
    var local = 1;
    Function("console.log(typeof local);")(); // logs undefined
    }());
  1.  

-高级Javascript编程学习笔记----Javascript编程及架构设计最应该注意的基本点的更多相关文章

  1. Linux Shell编程学习笔记——目录(附笔记资源下载)

    LinuxShell编程学习笔记目录附笔记资源下载 目录(?)[-] 写在前面 第一部分 Shell基础编程 第二部分 Linux Shell高级编程技巧 资源下载 写在前面 最近花了些时间学习She ...

  2. 多线程编程学习笔记——异步调用WCF服务

    接上文 多线程编程学习笔记——使用异步IO 接上文 多线程编程学习笔记——编写一个异步的HTTP服务器和客户端 接上文 多线程编程学习笔记——异步操作数据库 本示例描述了如何创建一个WCF服务,并宿主 ...

  3. javascript正则表达式 - 学习笔记

    JavaScript 正则表达式 学习笔记 标签(空格分隔): 基础 JavaScript 正则表达式是用于匹配字符串中字符组合的模式.在javascript中,正则表达式也是对象.这些模式被用于Re ...

  4. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  5. DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  6. ufldl学习笔记和编程作业:Feature Extraction Using Convolution,Pooling(卷积和汇集特征提取)

    ufldl学习笔记与编程作业:Feature Extraction Using Convolution,Pooling(卷积和池化抽取特征) ufldl出了新教程,感觉比之前的好,从基础讲起.系统清晰 ...

  7. ufldl学习笔记和编程作业:Softmax Regression(softmax回报)

    ufldl学习笔记与编程作业:Softmax Regression(softmax回归) ufldl出了新教程.感觉比之前的好,从基础讲起.系统清晰,又有编程实践. 在deep learning高质量 ...

  8. 多线程编程学习笔记——async和await(一)

    接上文 多线程编程学习笔记——任务并行库(一) 接上文 多线程编程学习笔记——任务并行库(二) 接上文 多线程编程学习笔记——任务并行库(三) 接上文 多线程编程学习笔记——任务并行库(四) 通过前面 ...

  9. 多线程编程学习笔记——async和await(二)

    接上文 多线程编程学习笔记——async和await(一) 三.   对连续的异步任务使用await操作符 本示例学习如何阅读有多个await方法方法时,程序的实际流程是怎么样的,理解await的异步 ...

随机推荐

  1. 从0 开始 WPF MVVM 企业级框架实现与说明 ---- 第二讲 WPF中 绑定

    说到WPF, 当然得从绑定说起,这也是WPF做的很成功的一个地方,这也是现在大家伙都在抛弃使用winform的其中一个主要原因,Binding这个东西从早说到完其实都说不完的,我先就做一些基本的介绍, ...

  2. hdu 5412 CRB and Queries

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5412 CRB and Queries Description There are $N$ boys i ...

  3. Linux下安装MySQLdb模块

    1,查看是否已安装MySQLdb模块 进入python的命令行,输入 import MySQLdb 如果没有报错,证明此模块已经安装,可以跳过以下步骤. 2,下载最新的MySQLdb安装包: wget ...

  4. js 获取随机数

    返回 m 到 n 的随机整数 <script type="text/javascript"> function randomNumber(m.n){ return Ma ...

  5. ubuntu添加自定义vga输出分辨率

    Ubuntu有点折腾人....但是在折腾之后发现它更加方便,而且懂得更多的东西 最近在调试一个视频采集芯片的驱动,主要是接收vga输入和hdmi输入,在实验的过程中遇到了一个恼火的问题,就是同一台电脑 ...

  6. VS2013中如何更改主题颜色(深色)和恢复默认的窗口布局

    1.通常情况下,我们会根据个人爱好更改VS2013的主题颜色,一开始我喜欢白色,后来我偏爱深色. 依次选择:工具->选项->常规->主题->深色->确定,ok 2.我们在 ...

  7. java基础学习之对象转型

    对象转型(casting): 1)一个基类的引用类型变量可以指向其子类的对象 2)一个基类的引用不可以访问其子类对象新增加的成员(属性和方法) 3)可以使用引用变量instanceof类名,来判断该引 ...

  8. 问题:ldconfig

    显示加载库文件libjli.so时候出错. 解决办法 1.find / -name 'libjli.so'文件 路径在:/data0/home/app/act/jdk/jdk1.7.0_15/jre/ ...

  9. IT服务系统组成

    软件+硬件+数据 + 运维人员 = IT服务系统 车 司机 乘客 修车 = 车模式 效率 系统 用户 业务 运维 = 信息化 效率 如果司机不会开车,没有人会修车就不会有车轮上的世界 同样没有人会运维 ...

  10. 清除IE中Ajax缓存,Chrome不需要

    做项目的时候,会遇到这种情况,通过ajax从后台获取的数据在chrome上显示的是最新的,而在IE上却是以前的数据,这是为什么呢,在我百般调试下终于发现原来是因为IE的ajax缓存的原因,于是加上这段 ...