精华 读过很多代码,却依然写不好的 JS
发布于 10 年前 作者 russj 8566 次浏览 最后一次编辑是 8 年前 来自 分享

JavaScript 语法简单,很多人都是上来看个例子就写,边搜索边写。所以很多基本的东西反而不是很了解。这里总结了一些东西希望有帮助。

变量名

变量名只能以字母和$_两个字符起始,非首字符还可以是数字。虽然变量名可以使用其他 unicode 字符,但是最好不要这么做。巨坑。

数据类型

JavaScript 是弱类型或叫动态类型。同个变量可以赋各种类型的值。感觉有点类似 c/c++ 的指针,可以指向任意类型。比如

var str = "a string";
str = 1; //原来是字符串,现在改为数值完全没有问题
str = [1, 'str',{'prop': 'val'}]; //改为数组也没有问题,而且一个数组可以保存不同类型的数据

发现每本讲 JavaScript 的书对其基本类型的分法都不一样。如果仅关心对变量求 typeof 的结果,这些结果只会是以下 6 种之一

1. number 数值。IEEE-754 double-precision (64 bit)
	typeof 1; 
    typeof NaN; //"number",NaN(Not a Number 非数值) 后面有更多介绍
    typeof Infinity; //也是 "number",无穷大
2. string 字符串。16 位 unicode
3. boolean 布尔。(1 bit)
4. object
	typeof [1,2]; //数组对象
    typeof {'s':1}; //字面量对象
    typeof null; //空,对象的一种特殊形式。
5. undefined 未定义
6. function 函数
	typeof function(){};//"function"

使用 typeof 的一点经验,曾经发现个 bug 是关于它的。类似如下:

var v1 = 4,
	v2 = 2;
typeof v1*v2; //以为会是 number,其实返回 NaN。
typeof v1+v2; //返回 "number2"

看了后一个应该很容易理解,因为 typeof 的优先权(precedence)高于 * + 等运算符号,所以是 “number”*2,返回 NaN,“number” + 2 返回 “number2”。使用时注意。

null 和 undefined

一般申明一个暂时不用赋值的变量两者都可以,默认是 undefined。但是如果涉及到变量的最终目的是指向一个对象,而且最终要保存到数据库,可能 null 会更合适些,因为毕竟 null 算是对象,如果没有赋值,保存后数据库也会是 null,但如果是 undefined,数据库就可能收不到值。

他们之间的关系:

null == undefined //true
null === undefined //false; 具体见下面的操作符部分

前面说的 null 是一种特殊的对象,因为虽然它的 typeof 结果是 object,但是没有其他对象都具有的 6 个方法:

1. constructor() 用于创建对象的构造函数
2. hasOwnProperty() 用于检查给定的属性在当前对象实例中是否存在,这个检查不包括实例原型。其中作为参数的属性名 propertyName 必须是字符串形式。例如:o.hasOwnProperty("name")。
3. isPrototypeOf(object) 用于检查传入的对象是否是另一个对象的原型
4. propertyIsEnumerable(propertyName) 用于检查给定的属性是否能够使用for-in语句来枚举
5. toString() 返回对象的字符串表示
6. valueOf() 返回对象的字符串、数值或布尔值表示。通常与toString()方法的返回值相同。

NaN 和 Infinity

NaN 和 Infinity ( 还有下面提到的判断 NaN 的方法 isNaN())都是全局对象的属性和方法,所以可以直接使用。

NaN(Not a Number 非数值)其实很少用,一般都是数学计算失败的返回值,以免抛出错误。比如 Math.sqrt(-1) 和 parseInt(“str”) 都会返回 NaN。 不过有一个特殊情况就是除以零。非零数除以零返回Infinity,但是 0/0 返回 NaN。

console.log(0/0); //输出 NaN
console.log(2/0); //输出 Infinity

NaN 最坑人的就是

NaN == NaN
NaN === NaN //两个判断结果都是 false

其实这个非要解释也能说得通。<code> typeof NaN </code> 返回 “number”,所以 NaN 是一种 ”number“,当然 <code> NaN !== NaN </code> 就该为真了。或者说 NaN is not Not a Number。你感受下。

要预防判断变量出现 NaN !== NaN,可以使用 !! 双重否定来把任何变量转换为布尔类型比较。例如:!!NaN === !!NaN 就是 true,符合常人逻辑了。!! 是 Boolean() 的简化版。

还可以使用 isNaN() 来判断是否是 NaN。使用例子:

isNaN( NaN ); //true
isNaN( 7 ); //false
isNaN( "7" ); //也是false. 因为可以转化为数值 7
isNaN( "str" ); //true. 不能转化为数值
isNaN( true ); //false. 可以转化为数值 1
isNaN( null ); //false. 可以转化为数值 0

关于数值转化的更多规则可以看其他资料,比如 这篇里的 Number 类型.

操作符

唯一值得注意的 == 和 ===。

== 判断值相等;=== 判断值和类型都要相等。 例如:

10 == ”10“;  //ture
10 === "10"; //false

另外,switch 是用的 ===。

if 判断

在程序里我们经常要使用条件语句来对变量进行比较和判断,这样就会涉及到各种数据类型转换为布尔值的规则。

在 JavaScript 里,以下会被转换为 false:

1. number 数值:0(包括-0) 和 NaN
2. string 字符串:"" 空字符串
3. boolean 布尔:false
4. object 对象:null
5. undefined 未定义:undefined

前面提到的 6 种 typeof 结果,只有其中的 5 项里的 6 个值会转换为 false。其他的都是 true。

在使用 if 时,如果期望为 true 的值是以上提到的 6 个值之外的任何值,就可以直接使用

if (var){ //没有必要使用 !!var;不过很多代码用 !!
	//true
};

但是如果要判断两个值是不是一样再进行下一步操作,例如

if (var1 === var2){
}

为了避免前面在 NaN 部分讲的 NaN !== NaN 逻辑不一致情况,可以使用 !! 双重否定来把任何变量转换为布尔类型之后再作比较。比如

if (!!var1 === !!var2){ // !!NaN === !!NaN 返回 true
}

小结

  1. 使用 !!var1 === !!var2 来判断变量是否相等. !! 是预防 NaN 出现违反逻辑。
  2. JavaScript 一共有 6 个可转换为假的值 :0 (-0); NaN; “”; false; null; undefined. 可以直接用 if(var) 来对变量进行判断。

转一个刚看到的帖子,关于 js 的字符串与数值计算: http://www.reddit.com/r/ProgrammerHumor/comments/2ubhql/please_dont_hate_me_javascript_devs/

> '5' - 3
2 // weak typing + implicit conversions = headaches
(弱类型 + 隐含转换 = 头疼)
> '5' + 3
'53' // Because we all love consistency
(因为我们都爱一致性)
> '5' - '4'
1 // string - string = integer. what?
(字符串 - 字符串 = 整型。什么?)
> '5' + + '5'
'55'
> 'foo' + +'foo'
'fooNaN' // Marvelous.
(妙不可言)
> '5' + - '2'
'5-2'
> '5' + - + - - + - - + + - + - + - + - - - '-2'
'52' // Apparently it's ok
(显然很好)
> var x = 3;
> '5' + x - x
50
> '5' - x + x
5 // Because fuck math
(因为滚他妈的数学)
14 回复
var v1 = 4,
    v2 = 2;
typeof v1*v2; //以为会是 number,其实返回 NaN。
typeof v1+v2; //返回 "number2"

这个好坑,还有最后写的,太绕了…

@think2011 是很绕。写短更花时间。写着一半觉得无趣了。

用coffee吧,另外还有一本书叫you don’t know js

很赞… 虽然我觉得最好的办法还是不写 JS.

@i5ting You-Dont-Know-JS 就是这本。。。Types & Grammar这章看崩溃

最后的计算题说说我的看法: 1、‘5’ - 3 ‘5’ + 3 ‘5’ - '4’ 这几个我这么理解,如果存在字符串,+ 会执行字符串相加,- 则会转型成整形计算 2、‘5’ + + ‘5’ ‘foo’ + +‘foo’ ‘5’ + - ‘2’ +、-放在字符串前会将该字符串转为整形 3、‘5’ + - + - - + - - + + - + - + - + - - - ‘-2’ 我不想说这个,这个从后往前一个一个算 4、 var x = 3; ‘5’ + x - x <==> ‘53’ - 3 <==>50 ’5’ - x + x <==> 2+3 <==> 5

@chuchangming 目测也就只能这么解释了,话说第三个我根本不想看…实际使用尽量避免这样的坑吧…

@think2011

typeof v1 * v2 === (typeof v1) * v2 === 'number' * 2 === NaN

()的作用和语句执行顺序

感觉其中某些碉堡的写法还是少用,都是邪恶魔法

果断跳Coffeescript的坑吧

哈哈 用coffee的路过

那个 typeof 就是各种莫名其妙, 还有那个 ==,已经被批判过很多次了啊楼主怎么还用。隐式类型转换,当然也各种莫名其妙。。 都是糟粕,不学不用。

另外 null 不是对象,是原始类型,虽然 typeof 说它是对象。

!!var1 === !!var2 够烦的。实际用到的可能很小吧。

回到顶部