汤姆大叔博客笔记【随时更新】

前端之家收集整理的这篇文章主要介绍了汤姆大叔博客笔记【随时更新】前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

1、忘记var的副作用(Side Effects When Forgetting var)

隐式全局变量和明确定义的全局变量间有些小的差异,就是通过delete操作符让变量未定义的能力。

这表明,在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性属性是可以通过delete操作符删除的,而变量是不能的:

@H_404_17@// 定义三个全局变量 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"

2、预解析:var散布的问题(Hoisting: A Problem with Scattered vars)

@H_404_17@ 反例 myname = "global"; 全局变量 func() { alert(myname); "undefined" var myname = "local"; alert(myname); "local" } func(); 等价于下面这段代码 myname = "global"; global variable func() { var myname; 等同于 -> var myname = undefined; alert(myname); "undefined" myname = "local"; alert(myname); "local"} func();

for-in循环(for-in Loops)

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

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

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

@H_404_17@for (var i in man) { if (man.hasOwnProperty(i)) { 过滤原型属性方法 console.log(i,":",man[i]); } } 反面例子: // for-in loop without checking hasOwnProperty() man) { console.log(i,":"方法。像是:

@H_404_17@if (Object.prototype.hasOwnProperty.call(man,i)) { 过滤 console.log(i,man[i]); } }

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

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

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

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

@H_404_17@ 警告: 通不过JSLint检测 in man) 过滤 console.log(i,man[i]); }

(不)扩展内置原型((Not) Augmenting Built-in Prototypes)

扩增构造函数的prototype属性是个很强大的增加功能方法,但有时候它太强大了。

增加内置的构造函数原型(如Object(),Array(),或Function())挺诱人的,但是这严重降低了可维护性,因为它让你的代码变得难以预测。使用你代码的其他开发人员很可能更期望使用内置的 JavaScript方法来持续不断地工作,而不是你另加的方法

另外,属性添加到原型中,可能会导致不使用hasOwnProperty属性时在循环中显示出来,这会造成混乱。

因此,不增加内置原型是最好的。你可以指定一个规则,仅当下面的条件均满足时例外:

  • 可以预期将来的ECMAScript版本或是JavaScript实现将一直将此功能当作内置方法来实现。例如,你可以添加ECMAScript 5中描述的方法,一直到各个浏览器都迎头赶上。这种情况下,你只是提前定义了有用的方法
  • 如果您检查您的自定义属性方法已不存在——也许已经在代码的其他地方实现或已经是你支持的浏览器JavaScript引擎部分。
  • 你清楚地文档记录并和团队交流了变化。

如果这三个条件得到满足,你可以给原型进行自定义添加,形式如下:

@H_404_17@if (typeof Object.protoype.myMethod !== "function") { Object.protoype.myMethod = () { 实现... }; }

注释(Writing Comments)

你必须注释你的代码,即使不会有其他人向你一样接触它。通常,当你深入研究一个问题,你会很清楚的知道这个代码是干嘛用的,但是,当你一周之后再回来看的时候,想必也要耗掉不少脑细胞去搞明白到底怎么工作的。

很显然,注释不能走极端:每个单独变量或是单独一行。但是,你通常应该记录所有的函数,它们的参数和返回值,或是任何不寻常的技术和方法。要想到注 释可以给你代码未来的阅读者以诸多提示;阅读者需要的是(不要读太多的东西)仅注释和函数属性名来理解你的代码。例如,当你有五六行程序执行特定的任务, 如果你提供了一行代码目的以及为什么在这里的描述的话,阅读者就可以直接跳过这段细节。没有硬性规定注释代码比,代码的某些部分(如正则表达式)可能注释 要比代码多。

函数表达式和函数声明

在ECMAScript中,创建函数的最常用的两个方法函数表达式和函数声明,两者期间的区别是有点晕,因为ECMA规范只明确了一点:函数声明必须带有标示符(Identifier)(就是大家常说的函数名称),而函数表达式则可以省略这个标示符:

  函数声明:

  function 函数名称 (参数:可选){ 函数 }

  函数表达式:

  function 函数名称(可选)(参数:可选){ 函数体 }

所以,可以看出,如果不声明函数名称,它肯定是表达式,可如果声明了函数名称的话,如何判断是函数声明还是函数表达式呢?ECMAScript是通过上下文来区分的,如果function foo(){}是作为赋值表达式的一部分的话,那它就是一个函数表达式,如果function foo(){}被包含在一个函数体内,或者位于程序的最顶部的话,那它就是一个函数声明。

@H_404_17@function foo(){} 声明,因为它是程序的一部分 var bar = function foo(){}; 表达式,因为它是赋值表达式的一部分 new function bar(){}; 表达式,因为它是new表达式 ((){ function bar(){} 声明,因为它是函数体的一部分 })();

函数声明@H_8_301@只能出现在程序@H_8_301@或函数体@H_8_301@内。从句法上讲,它们 不能出现在Block(块)({ ... })中,例如不能出现在 if、while 或 for 语句中。因为 Block(块) 中只能包含Statement语句, 而不能包含函数声明@H_8_301@这样的源元素。另一方面,仔细看一看规则也会发现,唯一可能让表达式@H_8_301@出现在Block(块)中情形,就是让它作为表达式语句@H_8_301@的一部分。但是,规范明确规定了表达式语句@H_8_301@不能以关键字function开头。而这实际上就是说,函数表达式@H_8_301@同样也不能出现在Statement语句或Block(块)中(因为Block(块)就是由Statement语句构成的)。 

 

@H_404_17@ 

猜你在找的JavaScript相关文章