Skip to content

JavaScript 鸡肋部分,参考javascript语言精粹

Notifications You must be signed in to change notification settings

smileyby/js-chicken-ribs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

鸡肋

==

JavaScript有两组相等运算符:===和!==,以及他们邪恶的孪生兄弟==和!=。===和!==这一组运算符会按照你期望的方式工作。如果两个运算数类型一直且拥有相同的值,那么===返回true,而!==返回false。而他们邪恶的孪生兄弟只有在两个运算符类型一直时才会做正确的判断,但如果两个运算数是不同的类型时,他们试图去转换其值的类型。转换的规则复杂且难以记忆。这里有一些有趣的例子:

'' == '0' // false
0 == ''   // true
0 == '0'  // true

false = 'false' // false
false == '0'    // true

false == undefined // false
false == null      // false
null == undefined  // true

' \t\r\n ' == 0    // true

== 运算符对传递性的缺乏值得我们警惕。我的建议是永远不要使用那对邪恶的孪生兄弟。相反,请始终使用 === 和 !==。所有以上的比较如果使用 === 运算符,结果都是false。

with语句

JavaScript提供了一个with语句。本意是想用来快捷地访问对象的属性。不幸的是,它们结果可能有事不可预料,所以应该避免使用它。

下面的语句

with (obj) {
	a = b;
}

和下面的代码做的是同样的事情:

if (obj.a === undefined) {
	a = obj.b === undefined ? a : obj.b;
} else {
	obj.a = obj.b === undefined? b : obj.b;
}

所以,它等于这些语句中的任何一条:

a = b;
a = obj.b;
obj.a = b;
obj.a = obj.b;

通过阅读程序代码,你不可能辨别出你会得到的是这些语句中的哪一条。它可能随着程序运行到下一步时发生变化。它甚至可能在程序运行过程中就发生了变化。如果你不能通过阅读程序而了解它将会做什么,你就无法确信它会正确地做你想要做的事情。

with语句在该们语言中存在,本身就严重影响了JavaScript处理器的速度,因为它阻止了变量名的词法作用域绑定。它的本意是好的,但如果没有它,JavaScript语言会更好一点。

eval

eval函数传递的一个字符串给JavaScript编译器,并且执行器结果。它是一个被滥用得最多的JavaScript特性。那些对JavaScript语言一知半解的人们最常用它。例如:如果你知道点表示法,但不知道下标表示法,就可能会这么写:

eval("myValue = myObject." + myKey + ";");

而不是这么写:

myValue = myObject[myKey];

使用eval形式的代码会更加难以阅读。这种形式将使得性能显著降低,因为它须运行编译器,但也许只是为了执行一个微不足道的赋值语句。它会让JSLint失效,因此该工具检测问题的能力也会显示降低。

eval函数还减弱了你应用程序的安全性,因为它给被求值的文本赋予了太多的权利。而且就像with语句执行的方式一样,它降低了语言的性能。

Function构造器和eval的另一种形式,所以它同样也应该避免使用。

浏览器提供的setTimeout和setInterval函数,他们能接受字符串参数或函数参数。当传递的字符串参数时,setTimeout和setInterval会像eval那样去处理。字符串参数形式也应该被避免使用。

continue语句

continue 语句跳到虚幻的顶部。我们发现一段代码通过重构移除continue语句之后性能都会得到线束改善。

switch贯穿

switch 语句的由来可以追溯到FORTRAN IV的go to语句。除非你明确地终端流程,否则每次条件判断后都会贯穿到下一个case条件。

一门语言最糟糕的特性不是那些显然很危险或无用的特性。那些特性和容易被避免。最糟糕的特性是带刺的玫瑰,他们是有用的,但也是危险的。

缺少块的语句

If 、while、 do或for语句可以接受一个括在花括号中的代码块,页可以接受单行语句。单行语句的形式是另一种带刺的玫瑰。它带来的好处是可以节约两个字节,但这是不是个好处值得商榷。他模糊了程序的结构,是的在随后的操作代码中可能很容易插入错误。例如:

if (ok)
t = true;

可能变成:

if (ok)
t = true;
advance();

它看起来像是要这样:

if (ok) {
	t = true;
	advance();
}

但实际上它本意却是:

if (ok) {
	t = true;
}
advance();

貌似在做一件事,但实际上却是在做另一件事的程序是非常难以理解清除的。严格规范并始终使用代码块会使得代码更容易理解。

++ --

递增和递减运算符是的程序员可以用非常简洁的风格去编码。比如在C语言中,他们是的用一行代码实现字符串的赋值成为可能:

for (p = src, q = dest; !*p; p++, q++) *q = *p;

事实上,这两个运算符容易促成一种不谨慎的编程风格。大多数的缓冲区溢出错误所造成的安全漏洞,都是由于像这样编码而导致的。

在我自己的实践中,我观察到,当我是用 ++ 和 -- 时,代码旺旺变得过于紧密,复杂和隐晦。因此,作为一条原则,我不在使用它们。我想那样会让我的代码风格变得更为整洁。

位运算符

JavaScript有着与Java相同的一套位运算符


& and 按位与
| or  按位或
^ xor 按位异或
! not 按位非
>>    带符号的右移
>>>   无符号的(用0补足)右移
<<    左移 

在Java里,位运算处理的是整数。JavaScript没有整数类型。它只有双精度的浮点数。因此,位操作符将他们的数字运算符先转换成整数,接着执行运算,然后在转换回去。在大多数语言中,这些为运算符接近于硬件处理而非常快。在JavaScript中,他们非但不是硬件处理,而且非常慢。JavaScript很少被用来执行位操作。

另一个结果是,在JavaScript程序中,&非常容易被误写为&&运算符。位运算符出现在JavaScript中降低了这门语言的冗余度,是的bug更容易被隐藏起来。

function 语句对比函数表达式

JavaScript既有 function 语句,同事也有函数表达式。这是令人困惑的,因为他们看起来好像相同的。一个 function 语句就是其值为一个函数的 var 语句的速记形式。

下面的语句:

function foo() {}

意思相当于:

var foo = function foo() {};

在整本书中,我一直使用的是第二种形式,因为它能明确表示foo是一个包含一个函数值的变量。要用好这门语言,理解函数就是数值是很重要的。

function语句在解析时会发生被提升的情况。这意味着不管 function 被放置在哪里,它会被移动到被定义时所在作用域的顶层。这放宽了函数必须先声明后使用的要求,而我认为这回导致混乱。在if语句中使用 function 语句也是被禁止的。结果表明大多数的浏览器都允许在if语句里使用 function 语句,但它们在解析时的处理上各不相同。那就造成了可移植的问题。

一个语句不能以一个函数表达式开头,因为官方的语法假定以单词 function 开头的语句是一个 function 语句。解决方法就是把函数表达式括在一个圆括号之中。

(function () {
	var hidden_varibale;
	// 这个函数可能对环境有一些影响,但不会引入新的全局变量。
})();

类型的包装对象

JavaScript 有一套类型的包装对象。例如:

new Boolean(false)

会返回一个对象,该对象有一个valueOf方法会返回被包装的值。这其实完全没有必要,并且有时还令人困惑。不要使用 new Boolean、new Number 或 new String。

此外也请避免 new Object 和 new Array。 可使用 {} 和 []来代替。

new

JavaScript的new运算符创建一个继承于其运算数的原型的新对象,然后调用该运算数,把心创建的对象绑定给this。这个运算数(它应该是一个构造器函数)一个机会在返回给请求者前去定义新创建的对象。

如果你忘记了使用此new运算符,你所得到的就是一个普通的函数调用,并且this被绑定到全局对象,而不是新创建的对象。那意味着当你的函数尝试去初始化新成员元素时它将会污染全局变量。那是一件非常糟糕的事情。而且没有编译时警告,也没有运行时警告。

按惯例,打算与new结合使用的函数应该命名为字母大写的形状,并且首字母大写的形式应该只用来命名那些构造器函数。这个约定给我们提供一个视觉线索,以帮助我们发现那些JavaScript语言自身经常忽略但却会带来昂贵的错误。

一个更好的对应策略就是根本不去使用 new

void

在很多语言中,void是一种类型,表示没有值。而在JavaScript,void是一个运算度,它接受一个运算数并返回undefined。这没有什么用,而且令人非常困惑。应避免使用它。

About

JavaScript 鸡肋部分,参考javascript语言精粹

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published