红宝书系列读书笔记(一)

前言:红宝书,即《JavaScript高级程序设计》一书,目前为第3版。这本书很合适新手入门,相比于《JavaScript权威指南》(犀牛书),它更容易帮助我们理解JavaScript,它从浅入深讲解了JavaScript,很多一开始难以理解的概念,都能通过这本书理解得更透彻。

基础概念

JavaScript由三部分组成:
ECMAScript、文档对象模型(DOM)、浏览器对象模型(BOM)

DOM的核心规定的是如何映射基于XML的文档结构
另外几种DOM标准:SVG、MathML、SMIL

文档模式:标准模式和混杂模式(诡异模式)IE6之前,浏览器渲染HTML文件的模式被称为诡异模式。

浏览器不支持JavaScript或js脚本被禁用时,使用<noscript>

标识符,就是指变量、函数、属性的名字,或者函数的参数。

ES5提出了“严格模式”,要在整个脚本中启用严格模式,可以在顶部添加:“use strict”。

ECMAScript 的变量是松散类型,所谓松散类型(弱类型)就是可以用来保存任何类型的数据。

var关键字明确地为函数变量设定作用域

JS有五种基本数据类型:undefined、null、boolean、Number和String;
一种复杂数据类型(引用类型):Object;

基本数据类型和复杂数据类型在存储上有区别,基本数据类型存储于栈;复杂数据类型,在堆中存储,在栈中存储堆指针

检测变量的数据类型——typeof

使用typeof检测未声明和为初始化的变量都是返回undefined
typeof 检测null值返回object (null==undefined)返回true

0除以0才返回NaN,正数除以0返回Infinity,负数除以0返回-Infinity
isNaN()函数判断是否“不是数值”

数值转换的函数:Number(),parseInt(),parseFloat(),分别转换为数字、整型、浮点型

String类型
字符字面量是指转义字符。转义字符当作一个字符长度。
ECMAScript中,字符串是不可变的。要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量。

转换为字符串的方式:toString()和转型函数string()[toString()返回的是字符串的副本]

object类型
Object的每个实例都具有下列属性和方法:
constructor:保存着用于创建当前对象的函数,即构造函数;
hasOwnProperty:用于检查给定的属性在当前对象实例中是否存在;
isPrototypeOf(object):用于检查传入的对象是否传入对象的原型;
propertyIsEnumberable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举;
toLocaleString(),toString(),valueOf();

操作符
递增和递减:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2;            //等于22
var num4 = num1+num2;                 //等于21
var s1="2";
var s2="z";
var b=false;
var f=1.1;
var o={
  valueOf:function(){
return -1;
  }
};
s1++;    //3
s2++;    //NaN
b++;     //1
f--;        //0.100000000000009(浮点舍入错误所致)
o--;       //-2

位操作符
按位非(~):本质是操作数的负值减一,

1
2
3
var num1=25;
var num2= ~num1;
alert(num2);        //"-26"

按位与(&)
按位或(|)
按位异或(^):只有一个1时才返回1,若对应的两位都是1或都是0,则返回0;

数值大小超过了ECMAScript数值的范围,则返回Infinity或-Infinity

1
2
3
4
Infinity * 0 = NaN;
Infinity * 非0数值结果是Infinity或-Infinity;
Infinity * Infinity = Infinity
Infinity / Infinity = NaN

如果是零被零除,结果是NaN
非零有限数被零除,结果是Infinity或-Infinity

1
2
3
Infinity +(-Infinity)= NaN
Infinity - Infinity = NaN
-Infinity - (-Infinity) = NaN

+0减-0等于-0
-0减-0等于+0

从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本;
引用类型的值是对象,保存在堆内存中,堆地址指针保存在栈内存中;
包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针。
基本类型的参数只能按值传递,而在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,局部变量变化会反映在函数的外部

typeof检测基本数据类型:typeof null 会输出object
typeof检测正则表达式时会输出function,但在IE和firefox中会输出object

instanceof检测引用类型(对象)

执行环境和作用域链
执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象。
执行环境有全局执行环境和函数执行环境之分。
全局变量和函数都是作为window对象的属性和方法创建的。

作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
作用域链的前端,始终是当前执行的代码所在环境的对象。全局执行环境的变量对象始终都是作用域链中的最后一个对象。
内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。
(通俗地讲,就是可以从里到外调用变量和函数,但外一层不能调用里面一层的)

延长作用域链的方法:
try-catch语句的catch块;
with语句(不推荐使用)。

Javascript没有块级作用域
所谓块级作用域,就是指循环语句块、条件语句块的执行环境,在JavaScript中是不存在的,JavaScript中只有全局作用域以及函数作用域。
(ES6中已支持块级作用域)

1
2
3
for(var i=;i<10;i++){
    //dosomething
}

在javascript里for语句创建的变量即使for循环执行结束后,也依旧会存在于循环外部的执行环境中。

查询标识符(变量、函数名、属性等):搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。

JavaScript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。
JavaScript中最常用的垃圾收集方式是标记清除,另外一种不太常见的垃圾收集策略是引用计数。

当数据不再有用,则最好通过将其值设置为null来释放其引用——这个做法叫做解除引用。

创建object实例的方式
使用new操作符后跟object构造函数;
使用对象字面量(不会调用object构造函数);
(对象字面量是定义对象的一种简写形式,也就是一种语法糖,目的在于简化创建包含大量属性的对象的过程)
eg:
var person={
name :”Peter”,
age : 22,
5 : true
};
这里的数值属性名会自动转换为字符串。

Array数组

创建数组的基本方式:
使用Array构造函数:var colors = new Array();
使用数组字面量表示法:var colors = [];
数组的length不是只读,通过设置这个属性,可以从数组的末尾移除项或向数组中添加新项。

1
2
var colors=["red","blue","green"];
colors[colors.length]="black";    //在末尾添加一种颜色

使用instanceof操作符和Array.isArray()方法检测数组

数组使用join()方法,则可以使用不同的分隔符来构建这个字符串;

1
2
3
var colors=["red","blue","green"];
alert(colors.join(","));
alert(colors.join("||"));     //red||blue||green

数组的栈方法:push()和pop(); //后进先出
push()方法可以接收任意数量的参数,把它们逐个添加到数组末尾,然后返回修改后的数组长度。
pop()方法则从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。

数组的队列方法:shift()和push(); //先进先出
push()方法在队列的末尾添加项,shift()方法在队列的前端移除项
shift()方法能够移除数组中的第一个项并返回该项,同时数组长度减1;

unshift()和pop()方法可以实现反向队列,即在数组的前端添加项,在数组的末端移除项。
unshift()方法在数组前端添加任意个项并返回数组长度。

数组重排序方法:reverse()和sort(),返回值都是排序后的数组;
sort()方法可以接收一个比较函数作为参数。

1
2
3
4
5
6
7
8
9
10
11
function compare(){
    if(value1 < value2){
        return -1;
    }else if (value1 > value2){
        return 1;
    }else{
        return 0;
    }
}
var values=[0,1,5,10,15];
values.sort(compare);

对于数值类型或者其valueOf()方法会返回数值类型的对象模型,可以使用更简单的比较函数:

1
2
3
function compare(value1, value2){
    return value2-value1;
}

concat()方法可以基于当前数组中的所有项创建一个新数组。
slice()方法可以基于当前数组中的一项或多个项创建一个数组。
slice()方法接受一或两个参数,即要返回项的起始和结束位置。
(如果slice()方法的参数有一个负数,则用数组长度加上该负数来确定相应的位置,如果结束位置小于起始位置,则返回空数组)

最强大的数组方法—splice()
splice()的主要用途是向数组的中部插入项。
使用splice的三种方式:
删除:可以删除任意数量的项,需指定2个参数:要删除的第一项的位置和要删除的项数。例如,splice(0,2)会删除数组前两项。

插入:可以向指定位置插入任意数量的项,需提供3个参数:起始位置,0(要删除的项数)和要插入的项。如果要插入多个项,可以传入第四、第五,以至任意多个项。例如,splice(2,0,”red”,””green”)会从当前数组位置2开始插入字符串”red”和”green”;

替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,需指定3个参数:起始位置,要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。例如,splice(2,1,”red”,””green”)会删除当前数组位置2的项,然后再从位置2 开始插入字符串”red”和”green”;

数组的位置方法:indexOf()和lastIndexOf()这个两个方法都接收两个参数:要查找的项和(可选的)表示查找起点位置的索引;
两个函数返回的都是要查找的项在数组中的位置,或者在没找到的情况下返回-1。
在比较第一个参数与数组中的每一项是,会使用全等操作符,也就是说,要求查找的项必须严格相等。

数组的迭代方法:
every(),filter(),forEach(),map(),some()。
every()和some()都是对数组中的每一项运行给定的函数,但every()函数只有每一项都是true,才返回true;
而some()则是数组中有一项运行结果是true,则返回true。
filter()函数是会过滤数组中的一些项,将符合条件的项组成一个新的数组,并返回这个数组。
map()函数是将数组中的每一项进行一些操作,然后将操作结果作为新数组中的每一项,并返回这个新数组。

数组的归并方法:reduce()和reduceRight(),这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。
reduce()从头开始逐个遍历,reduceRight()则从数组的最后一项开始,向前遍历到第一项。
都接收两个参数:在每一项调用的函数和(可选的)作为归并基础的初始值。
eg:使用reduce()函数可以求得数组中所有值之和的操作。
var values=[1,2,3,4,5];
var sum=values.reduce(function(prev,cur,index,array){
return prev + cur ;
});
reduce()和reduceRight()接收的一个参数—函数接收4个参数,前一个值,当前值,项的索引和数组对象。

Date类型

使用valueOf方法返回的是日期的毫秒表示,所以可以使用比较操作符来比较日期值。
日期格式化方法:
toDateString()——以特定于实现的格式显示星期几、月、日和年;
toTimeString——以特定于实现的格式显示时、分、秒和时区;
toLocaleDateString——以特定于地区的格式显示星期几、月、日和年;
toLocaleTimeString——以特定于实现的格式显示时、分、秒;
toUTCString——以特定于实现的格式完整的UTC日期。

RegExp类型

Javascript通过RegExp类型来支持正则表达式。

1
var expression = / pattern / flags;

其中模式(pattern)部分可以是任何简单或复杂的正则表达式,每个正则表达式都可
带有一个或多个标志(flags)
如下三种标志:
g:表示全局模式,即模式将被应用于所有的字符串,而非在发现第一个匹配项是立即停止;
i:表示不区分大小写模式;
m:表示多行模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。

RegExp实例属性
global: 布尔值,表示是否设置了g标志
ignoreCase:布尔值,表示是否设置了i标志
lastIndex:整数,表示开始搜索下一个匹配项的字符位置
multiline:布尔值,表示是否设置了m标志
source:正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。

RegExp实例方法:
exec(),只接受一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组,在匹配失败时返回null;
返回的数组包含两个额外的属性:index和input。index表示匹配项在字符串中的位置,而input则是应用正则表达式的字符串。

1
2
3
4
var test="mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi;
var matches=pattern.exec(test);

第二个方法是test()方法,接受一个字符串参数,在模式与该参数匹配的情况下返回true;否则返回false.

1
2
3
4
5
6
var text = "000-00-0000";
var pattern = /\d{3}-\d{2}-\d{4}/;
if(pattern.test(text)){
    alert("This pattern was matched.");
}

Function类型

函数实际上是对象,函数名实际上是一个指向函数对象的指针。
函数内部有两个特殊对象:argumentsthis.
arguments的主要用途是保存函数参数,该对象有一个属性——callee,该属性是一个指针,
指向拥有这个arguments对象的函数。
使用arguments.callee可以消除函数的执行与函数名的紧密耦合。

1
2
3
4
5
6
7
function factorial(num){
    if(num<=1){
        return 1;
    }else{
        return num*arguments.callee(num-1);    //arguments.callee()等同于factorial()
    }
}

this对象也相当重要,详情看JS-this笔记。
ECMAScript 5还规范了另一个函数对象属性——caller。
这个属性保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为null。

1
2
3
4
5
6
7
function outer(){
    inner();
}
function inner(){
    alert(inner.caller);    //输出outer()函数的源码。
}
outer();

outer调用了inner(),所以inner.caller就指向了outer()。
为了实现更松散的耦合,可以通过arguments.callee.caller来访问相同的信息。

1
2
3
4
5
6
7
function outer(){
    inner();
}
function inner(){
    alert(arguments.callee.caller);    //输出outer()函数的源码。arguments.callee.caller等同于outer
}
outer();

总结:arguments.callee是指向拥有arguments对象的那个函数,而arguments.callee.caller是指向调用该函数的函数

每个函数都包含两个属性:lengthprototype
length属性是表示函数希望接收的命名参数的个数。
prototype属性是不可枚举的,使用for-in无法发现。
每个函数都包含两个非继承而来的方法:apply()和call()。这两个函数可以扩充函数赖以运行的作用域。

ps:在严格模式下,未指定环境对象而调用函数,则this值不会转型为window,this值是undefined

ECMAScript 5还定义了bind()方法,这个方法会创建一个函数的实例,其this值会被绑定传给bind()函数的值。

1
2
3
4
5
6
7
window.color="red";
var obj={color : "blue"};
function sayColor(){
    alert(this.color);
}
var objSayColor=sayColor.bind(obj);    //将sayColor()函数绑定到obj对象,this指向obj。
objSayColor();

基本包装类型

Boolean、Number、String
实际上,每当读取一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,
从而让我们能够调用一些方法来操作这些数据。

引用类型和基本包装类型的主要区别是对象的生存周期。
对基本包装类型的实例调用typeof会返回“object”,而且所有基本包装类型的对象都会被转换成布尔值true.

布尔表达式中的所有对象都会被转换为true.

1
2
3
var falseObj = new Boolean(false);
var result = falseObj && true;
alert(result);    //true

Number 类型
toFixed()方法,按照指定的小数位返回数值的字符串表示,传入一个参数,是指定显示几位小数。
toExponential()方法,返回以指数表示法(e表示法)表示的数值的字符串形式。
toPrecision()方法返回某个数值的最合适的格式。

String类型
1.字符方法:
charAt():返回以单字符字符串的形式返回给定位置的那个字符
charCodeAt():返回给定位置的那个字符的字符编码

ECMAScript 5 还定义了另一种访问个别字符的方法,使用方括号加数字索引来访问字符串中的特定字符
eg:var str=”helloworld”;
alert(str[1]); //输出’e’

2.字符串操作方法
concat():用于将一或多个字符串拼接起来,返回拼接得到的新字符串。
(在日常开发中更多的是使用加号操作符+来拼接字符串)

slice(),substring(),substr()
他们都接收两个参数,slice和substring接收的是起始位置和结束位置(不包括结束位置),
而substr接收的则是起始位置和所要返回的字符串长度。
当接收的参数是负数时,slice会将它字符串的长度与对应的负数相加,结果作为参数;
substr则仅仅是将第一个参数与字符串长度相加后的结果作为第一个参数;
substring则干脆将负参数都直接转换为0。

3.字符串位置方法
查找子字符串:indexOf()和lastIndexOf().

4.trim()方法
ECMAScript 5中定义了trim()方法,这个方法会创建一个字符串的副本,删除前置以及后缀的所有空格,然后返回结果。

5.字符串大小写转换方法
toLowerCase()、toLocaleLowerCase() //转换为小写
toUpperCase()、toLocaleUpperCase()//转换为大写

6.字符串的模式匹配方法
match():只接收一个参数,要么是一个正则表达式,要么是一个RegExp对象。
search():唯一参数与match()方法的参数相同,返回字符串中第一个匹配项的索引;如果没有匹配项,则返回-1;
replace():接收两个参数:第一个参数可以上RegExp对象或字符串,第二个参数是一个字符串或函数;
split():可以基于指定的分隔符将一个字符串分割成多个子字符串。

7.localeCompare()方法
使用本地规则比较字符串string1与string2,并返回比较结果
如果string1小于string2,返回-1
如果string1大于string2,返回1
如果string1等于string2,返回0

8.fromCharCode()方法
接收一或多个字符编码,然后将它们转换成一个字符串。

单体内置对象

Global和Math对象。
所有在全局作用域中定义的属性和函数,都是Global对象的属性。
isNaN(),isFinite(),parseInt(),parseFloat(),实际上都是Global对象的方法(在ES6中,parseInt()和parseFloat()是属于Number的方法)。
此外,Global还有一些其他方法:
1.URI编码方法
encodeURI() , encodeURIComponent(); //对URI进行编码
decodeURI() , decodeURIComponent(); //对URI进行解码

2.eval()方法
将字符串解析为javascript代码。
ps:不推荐使用eval(),会损耗性能,还会造成安全问题,如代码注入。

3.window对象
Web浏览器都是将Global对象作为window对象的一部分加以实现。

Math对象
min()和max()方法,求最小和最大值;
舍入方法:向上舍入Math.ceil(),向下舍入Math.floor(),标准舍入(也就是四舍五入)Math.round().

random(),求随机数
值 = Math.floor(Math.random()*可能值的总数+第一个可能的值).例如产生1~10的随机数:

1
Math.random() * 10 + 1

坚持原创技术分享,您的支持将鼓励我继续创作!