最小全局变量

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

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

全局变量问题

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

不推荐写法:

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

推荐写法:

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

Var的好处

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

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

如代码示例:

// 定义三个全局变量
var global_var = 1;
global_novar = 2; // 反面教材
(function () {
global_fromfunc = 3; // 反面教材
}()); // 试图删除
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true // 测试该删除
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"

访问全局对象

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

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

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

单Var模式

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

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

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

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

4.少代码。

function func() {
var a = 1,
b = 2,
sum = a + b,
myobject = {},
i,
j;
// function body...
}

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

预解析:var散布的问题

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

// 反例
myname = "global"; // 全局变量
function func() {
alert(myname); // "undefined"
var myname = "local";
alert(myname); // "local"
}
func();

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

for循环

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

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

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

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

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

for-in循环

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

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

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

思考下面一段代码:

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

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

// 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上的方法。像是:

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

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

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”干点什么):

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

要记住eval()是魔鬼、

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

// 反面示例
var property = "name";
alert(eval("obj." + property)); // 更好的
var property = "name";
alert(obj[property]);

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

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

// 反面示例
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000); // 更好的
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"

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

-高级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. python 小技巧(import模块、查询类继承关系、安装包)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在这里列举一些我使用Python时积累的小技巧.这些技巧是我在使用Python过程 ...

  2. HDU1006

    Problem Description The three hands of the clock are rotating every second and meeting each other ma ...

  3. DB2缓冲池、表空间

    在DB2中建立表空间得指向该表空间所属缓冲池,否则表空间指向默认缓冲池 1.缓冲池 1.1 创建缓冲池 语法:CREATE BUFFERPOOL <bp_name> SIZE <nu ...

  4. Redis 五:配置主从复制功能

    redis的主从复制事实上是非常简单的一件事情,甚至比mysql的配置还简单,因为基本不需要在主服务器上做任何操作 我们在同一台服务器上开不同的端口进行测试操作(安装部分就不说啦,前面的文章有::) ...

  5. hdu 3530 Subsequence

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=3530 Subsequence Description There is a sequence of i ...

  6. [SRH.Docker] HBase Java 第一天学习记录

    主要对HBase Table 的 简单操作, 直接上代码吧!!! http://pan.baidu.com/s/1hqzTTze       ui92

  7. RTFM

    RTFM是一个网络语言,意思是:“去读那些他妈的手册”(Read The Fucking Manual),这句话通常用在回复那些只要查阅文件就可以解决,拿出来提问只是浪费别人时间的问题.

  8. UILabel的相关属性设置

    在iOS编程中UILabel是一个常用的控件,下面分享一下UILabel的相关属性设置的方法. 很多学习iOS6编程都是从storyboard开始,用到UILabel时是将控件拖到storyboard ...

  9. VS2012 常用web.config配置解析之自定义配置节点

    在web.config文件中拥有一个用户自定义配置节点configSections,这个节点可以方便用户在web.config中随意的添加配置节点,让程序更加灵活(主要用于第三方插件的配置使用) 自定 ...

  10. c/c++常用代码--使用libcurl下载文件

    #pragma once #include <stdio.h>#include <stdlib.h> #include <curl/curl.h> #ifdef   ...