原文链接:https://github.com/vqun/blog/issues/1
- 基本概念
===
1.1 变量
ECMA变量是松散型的,爱保存啥类型的数据都行。变量申明使用的是var,当然也可以不用。使用var,申明局部变量,不使用申明全局变量。不使用var是为JS界所鄙视的,所以,建议申明变量时,带上var。
function f(){
var x = 1; // x是局部变量,只在f
y = 2; // y是全局变量
}
f();
alert(x); // 报错
alert(y); // 2(当然,前提是你注释了上一句话)
变量有三个阶段:申明、赋值和使用。
申明和赋值是两个完全不同的概念,解释器对于这两个阶段也是完全不同的,申明是在代码期(写代码时期,业界喜欢叫预编译还是啥的),赋值是在运行期。
var a; // 这是申明
a = 1; // 这是赋值
var b = 2; // 这句话,在代码期,解释器只做了var b;在运行期,做了b = 2
这也牵扯一下JS界都喜欢问的一个题:
alert(c); // undefined
var c = 3;
之所以是undefined,涉及到了所谓的“Hoisting”(变量提升)。变量提升里说了,变量申明会被提前,于是乎上述代码被等同于:
var c;
alert(c);
c = 3;
这其实是因为申明和赋值在两个不同阶段。
1.2 区分大小写
这个你懂的
1.3 标识符
说一点,一般认为的标识符,是非保留字,以_、$、字母开头。实际上,还可以是Unicode、ASIIC,因此,连中文都可以直接作为标签符的,例如:
var 你好 = 1;
alert(你好);
var \u7788 = 2;
alert(\u7788);
上面两个都可以正常运行。当然,这种用写法在实际编程里是不推荐的,只是曾经有吃饱没事干的面试官出过这种面试题,算是普及一下
1.4 注释
两种注释风格,和C/C++类似,单行注释和多行注释:
// 单选注释
/*
* 多行注释
*/
1.5 分号
关于分号,编程习惯就是在语句的结尾加分号。当然,如果你想装逼,好好看ECMA262,里面告诉你了什么时候要加分号,什么时候不用。
1.6 关键字和保留字
曾经有人问,关键字和保留字有什么区别。其实,从实际角度讲呢,因为你都不会去当成标识符,所以没区别;概念角度讲呢,关键字是真不能用(加了引号可以),保留字呢,目前可用,以后估计就不能用了。
1.7 数据类型
五种基本类型+一种引用类型。五种基本类型:Undefined、Null、Number、String、Boolean,一种引用类型:Object。
typeof:这是一个比较让人无语的操作符,以致于业界都不喜欢用它来判断数据类型。其实,让人无语,主要是因为对null,array使用typeof时,返回的不是期望的“null”和“array”,而是“object”。这个其实没什么,从理解角度讲,是挺合理的,null本身就是代表的空对象,array本身在JS里根本没这个类型。当然,Number、Boolean等直接new出来的,typeof结果也是“object”。
1.8 操作符
操作符都有返回值。合理利用这个返回值,可以提升你的代码逼格。比如,一般人都这么写:
var obj = {
"a": {
"name": "hello",
"value": 1
},
"b": {
"name": "world",
"value": 2
}
}, tmp, n, ret = {};
for(var k in obj){
tmp = obj[k];
n = tmp.name;
!!n && ret[n] = tmp;
}
博主喜欢这么装逼:
var obj = {
"a": {
"name": "hello",
"value": 1
},
"b": {
"name": "world",
"value": 2
}
}, tmp, n, ret = {};
for(var k in obj)
!!(n = (tmp = obj[k]).name) && ret[n] = tmp;
有木有觉得逼格一样子提升了好几个档次,连for循环的花括号都省了。。。其实,我会告诉你,只是因为后者的性能更高,所以我才用的。
1.9 语句
语句包括:if、do-while、while、for、for-in、label、break和continue、with以及switch。除了with,其他的都很简单,只要记得JS没有块作用域就可以了。
关于with,“with会在原作用域链里插入新的作用域,影响性能”这句话是JS界里流行的几句话[1]之一。确实,因为作用域链的问题,with存在性能问题,不过,很多模版引擎却用了with来实现,如underscoreJs内置的template,其“编译”完之后的代码里,就用了with来遍历对象,以达到在模版里直接使用对象的属性名。
[1]JS界里流行的几句话:
1. 变量申明会被提到最前面
2. eval是邪恶的
3. with会在原作用域链里插入新的作用域,影响性能
1.10 函数
函数定义有三种方式:函数申明、函数表达式和构造函数。
// 函数申明
function f(){
console.log("declaration");
}
// 函数表达式
var f = function(){
console.log("expression");
}
// 构造函数
var f = new Function("console.log('constructor')");
函数申明会在预编译阶段就确定,表达式和构造函数是在运行时确定。这再牵扯一下业界面试题喜欢玩的一个题:
alert(a); // 输出那个function
var a = 1;
alert(a); // 输出1
function a(){
console.log("function")
}
alert(a); // 输出1
上述代码中,由于在预编译时,function a(){...}确定了,因此,在运行时,第一个alert就将这个函数申明alert出了,而第二个第三个alert,就很明显了。