写在前面
作为一个工作了6年的前端,犀牛书(《Javascript权威指南》)没有完整读过一遍,似乎很不合格。最近也被别人问到一些问题,心里总不太有把握。
现如今框架层出,但是永远最重要的还是基础。于是决定,将这本书读完,消化整理后,完成这份精简版的更利于记忆的基础系列笔记,给我自己以及需要提高javascript基础的小伙伴们。
为了方便查找对应的知识点详情,本系列沿用了犀牛书中的章节结构和标识,跳过了过于基础的内容。
词法结构
2.1 字符集
Javascript是区分大小写的语言。online
,Online
,onLine
,OnLine
是四个不同的变量名。
HMTL 不区分大小写。
2.2 注释
Javascript支持两种注释,单行//
和多行/**/
//这里是单行注释
/*
*这个是多行注释
*下一行
*/
2.3 直接量
直接量(literal)是程序中直接使用的数据值。下面是一些直接量的例子:
12 //数字
1.2 //小数
"hello" //字符串
true //布尔值
null //空
/javascript/gi //正则表达式直接量
2.4 标识符和保留字
标识符
标识符用来对变量和函数进行命名。命名规则:
~ | 字母 | 数字 | _ | $ |
---|---|---|---|---|
开头 | √ | × | √ | √ |
后续 | √ | √ | √ | √ |
允许标识符中出现Unicode字符全集中的字母和数字。
保留字
Javascript把一些标识符拿出来做关键字。因此这些不能再作为标识符(这里不详细列出保留字)。
2.5 可选的分号
使用;
将语句分开。
类型、值和变量
3.1 数字
Javascript不区分整数值和浮点数值,所有数字均用浮点数值表示。
3.1.3 算数运算
算数运算在溢出(overflow)、下溢(underflow)或被0整除都不会报错。会显示Infinity
和-Infinity
来表示无穷大和负无穷大。如果像0/0没有意义,结果是非数字(not-a-number),显示NaN
。
1/0 //=> Infinity
-1/0 //=> -Infinity
0/0 //=> NaN
1/Infinity //=> 0
非数字值(NaN)有一点特殊:它和任何值都不相等,包括自身。
var x=0/0 //=> NaN
x==NaN //=> false
两个函数isNaN()
和isFinite()
判断是否非数字和有限数。
var x=0/0;
isNaN(x); //=> true
var y=1/0 //=> Infinite
isFinite(y) //=> false;
isFinite(5) //=> true;
正零和负零相等,正无穷大和负无穷大不等:
var x=0,y=-0;
x==y //=> true
1/x==1/y //=> false;
3.1.4 二进制浮点数和四舍五入错误
上面提到Javascript中所有数字均用浮点数值表示,而实数有无数个,但通过浮点数的形式只能表示有限个数。即,使用实数时,常常只是真实值的一个近似表示。
Javascript采用IEEE-754浮点数表示法,是一种二进制表示法,不能精确表示类似0.1这种十进制分数。
var x = .3 - .2; //=> 0.09999999999999998
var y = .2 - .1; //=> 0.1
x==y //=> false
为避免该问题,在进行重要的金融计算时,使用大整数计算。用整数“分”,而非小数“元”进行基于货币单位的运算。
var x = 3 - 2; //=> 1
var y = 2 - 1; //=> 1
x==y //=> true
3.2 文本
3.2.1 字符串直接量
字符串直接量是由''
或""
括起来的字符序列。
ECMAScript 5中,字符串直接量可以拆分成数行,必须以反斜线\
结束。
var myString1="<div>\
<a>link</a>\
</div>";
3.2.2 转义字符
常用的转义字符:
转义字符 | 含义 |
---|---|
\n | 换行符 |
\" | 双引号 |
\' | 单引号 |
\\ | 反斜线 |
var str='Two\nLines';
//=> "Two
// Lines"
3.2.3 字符串的使用
使用+
进行字符串连接。
字符串的length属性和方法(indexOf, split等等)以及正则表达式后面再介绍。
3.3 布尔值
只有两个值:true
和false
。
任意Javascript的值都可以转换为布尔值,下列会转换成false
:
undefined
null
0
-0
NaN
""//空字符串
3.4 null和undefined
~ | 描述 | 类型(typeof) |
---|---|---|
null | 关键字,表示空值 | object |
undefined | 值空缺,变量没有初始化 | undefined |
如何区分这两个值?使用严格相等运算符===
null == undefined //=> true
null === undefined //=> false
如果需要将“空”赋值给变量或属性或作为参数传入参数,使用null
。
3.6 包装对象
引例:
var str="hello";
str.length //=> 5
问:字符串不是对象,为什么会有属性?
答:将字符串值通过调用new String(str)的方式转换成对象,并继承了字符串的属性。
字符串、数字和布尔型的属性都是只读的,不能给他们定义新属性,是有别于对象的。
var s="test";
s.len=4;
var t = s.len; //=> undefined
可通过String(), Number()或Boolean()构造函数显式创建包装对象。他们和原始值不严格相等。
var s='test', n=1, b=true;
var S = new String(s);
var N = new Number(n);
var B = new Boolean(b);
S==s //=> true
S===s //=> false
3.7 不可变的原始值和可变的对象引用
~ | 类型 | 描述 | 比较 |
---|---|---|---|
原始值 | undefined、null、布尔值、数字、字符串 | 不会更改:任何方法都无法更改 | 值相等则相等 |
对象 | 数组、函数 | 值可修改 | 引用同一个基对象时,才相等;两个对象包含同样属性及值并不相等 |
原始值不会更改示例:
var str="hello";
str.toUpperCase(); //=> "HELLO"
str //=> "hello"
对象比较示例:
var x={a:1},y={a:1};
x==y //=> false: 两个单独的对象永不相等
var x=[],y=[];
x==y //=> false: 两个单独数组永不相等
var x={},y=x;
x==y //=> true: 引用相同
那么如何判断两个对象是否含有同样的属性呢?遍历。
function equalArrays(a,b){
if(a.length != b.length){
return false;
}
for(var i=0;i< a.length;i++){
if(a[i] !=b[i]){
return false;
}
}
return true;
}
var x={a:1},y={a:1};
equalArrays(x,y); //=> true: 属性值都相等
3.8 类型转换
Javascript中的取值非常灵活,会根据期望进行转换,例如:
2 + 1 //=> 3
"2" + 1 //=> "21"
"2" - "1" //=> 1
"2" * "1" //=> 2
"2" - "Hi" //=> NaN
true + true //=> 2
下面这几个类型转换需要注意:
值 | 转换为数字 |
---|---|
undefined | NaN |
null | 0 |
“”(空字符串) | 0 |
true | 1 |
false | 0 |
3.8.1 转换与相等性
由于Javascript可以做灵活的类型转换,因此==
相等运算符也会随相等的含义灵活多变。
"0" == 0 //=> true: 比较前[字符串]转成[数字]
0 == false //=> true: 比较前[布尔值]转成[数字]
"0" == false //=> true: 比较前[字符串]和[布尔值]都转成[数字]
===
恒等运算符在判断相等时不做类型转换。
注意:一个值转换为另一个值并不意味两值相等。
null == false //=> false
undefined == false //=> false
3.8.2 显式类型转换
- 显示类型转换方法
Boolean()
、Number()
、String()
、Object()
除了null和undefined之外任何值都具有toString()
方法。
Number("5") //=> 5
String(false) //=> "false" 或者使用 false.toString()
Boolean([]) //=> true, 注意Boolean("")是false
Object(3) //=> new Number(3)
- 隐式转换运算符
3 + "" //=> "3" 数字 -> 字符串
+"3" //=> 3 字符串 -> 数字
!!("") //=> false 转成布尔型,相当于Boolean(""),注意是【双感叹号】
数字与字符串转换方法
number-to-string
toString()
方法接受转换基数(radix)的可选参数。默认是十进制。var n= 10; n.toString(2) //=> "1010" n.toString(16) //=> "a"
string-to-number
这三个方法都会四舍五入或填充0。
函数名称 作用 参数含义 默认情况 toFixed()
保留几位小数 小数个数 四舍五入为整数 toExponential()
使用指数计数法 小数个数 保留全部小数 toPrecision()
保留有效数字位数 有效数字位数 原值 var n=12345.6789; n.toFixed() //=> "12346" n.toFixed(1) //=> "12345.7" n.toFixed(5) //=> "12345.67890" n.toExponential() //=> "1.23456789e+4" n.toExponential(1) //=> "1.2e+4" n.toPrecision() //=> "12345.6789" n.toPrecision(7) //=> "12345.68"
上述这些方法只能基于十进制数进行转换,且不能出现非法的尾随字符。下面介绍两个函数:
parseInt()
只解析整数,如果字符串前缀为“0x”或“0X”解析为十六进制数。可接受第二个参数为转换基数。parseFloat()
可解析整数和浮点数。他们都会跳过任意数量的前导空格,并忽略数字字符后面的内容,且不进行四舍五入。
parseInt("123.8") //=> 123: 去掉小数位 parseInt("0xff") //=> 255: 解析十六进制 parseInt(" 345.789 meters") //=> 345: 忽略前导空格和数字之后的内容 parseInt(".1") //=> NaN: 不能以非数字开头 parseInt("11.6",2) //=> 3: 二进制整数 parseFloat("$123.6") //=> NaN: 不能以非数字开头 parseFloat(".1345 meters") //=> 0.1345
3.8.3 对象转换为原始值
toString()
返回一个反映这个对象的字符串。
[1,2,3].toString() //=> "1,2,3" new Date(2010,0,1).toString() //=> "Fri Jan 01 2010 00:00:00 GMT+0800 (CST)"
valueOf()
如果存在任意原始值,它就默认将对象转换为表示它的原始值。
var d=new Date(2010,0,1) //=> 2010年1月1日 d.valueOf() //=> 1262275200000
日期对象与运算符的运行结果:
var dateNow= new Date();
typeof(dateNow + 1) //=> "string" : "+"将日期转换为字符串
typeof(dateNow - 1) //=> "number" : "-"使用对象到数字的转换
dateNow == dateNow.toString() //=> true: 隐式的和显式的字符串转换
dateNow > (dateNow - 1) //=> true: ">"将日期转换为数字
3.9 变量声明
使用var声明变量,在存入值之前,初始值是undefined。
ECMAScript 5严格模式中,给一个没有声明的变量赋值也会报错。非严格模式下,会给全局对象创建一个同名属性。
3.10 变量作用域
一个变量的作用域(scope)是源代码中定义这个变量的区域。
全局变量拥有全局作用域;在函数内声明的变量以及函数参数都是局部变量。局部变量优先级高于同名的全局变量。
var scope = "global";
function checkscope(){
var scope = "local";
return scope;
}
checkscope() //=> "local"
3.10.1 函数作用域和声明提前
Javascript中没有块级作用域(block scope),取而代之的是函数作用域(function scope)。
Javascript特性(非正式名称)声明提前(hoisting),函数里声明的所有变量都被“提前”至函数体的顶部。
var scope = "global";
function fn(){
console.log(scope) //=> undefined
var scope = "local";
console.log(scope); //=> local
}
等价于:
var scope = "global";
function fn(){
var scope;
console.log(scope) //=> undefined
scope = "local";
console.log(scope); //=> local
}
3.10.2 作为属性的变量
全局变量实际是全局对象的一个属性。当使用var声明变量时,这个属性不可配置,即无法通过delete删除。
var truevar = 1; //声明一个不可删除的全局变量
fakevar = 2; //创建全局对象的一个可删除的属性
this.fakevar = 3;
delete truevar //=> false: 变量并没有被删除
delete fakevar //=> true: 变量被删除
delete this.fakevar //=>true: 变量被删除
3.10.3 作用域链
每段Javascript代码都有一个与之关联的作用域链(scope chain)。这个作用域链是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量。
需要查找某个变量时(这个过程叫做“变量解析”),会从链中的第一个对象开始查找,如果没有会继续查找链上的下一个对象。 如果不存在,则抛出引用错误(ReferenceError)异常。