第5章 引用类型
5.1 Object类型
使用对象字面量定义函数时,最后一个属性后面不要添加逗号。如
var person={
name:"NIck",
age:29
};
5.2 Array类型
Array.isArray(),确定某个值是否是数组,通常用于条件语句。
toString()、valueOf()、toLocaleString(),返回由数组中每个值的字符串形式拼接而成的一个以逗号分隔的字符串。
join(),接收分隔符参数,返回以这个分隔符分隔的数组字符串。不传入值或传入undefined,默认以逗号分隔。
栈方法,push()末端推入,pop()弹出末项,后进先出(LIFO)。
队列方法,shift()移除第一项,push()末端推入,先进先出(FIFO)。
unshift()数组前端添加任意项,pop()弹出末项,先进后出。
reverse(),反转数组项的顺序。
sort(),按升序排列数组项。需传入比较函数sort(compare)。如
function compare(value1,value2){
if(value1value2){
retrun 1;
}else return 0;
}
var values=[0,1,5,10,15];
values.sort(compare);
concat(),基于当前数组所有项创建新数组。接收0或多个数组作为参数。
slice(),基于当前数组中一或多个项创建新数组。接收1或2个参数,要返回的项的起始和结束位置。返回起始至结束位置之间的项但不包括结束位置的项。
splice(起始位置,删除的项数,要插入的项),返回原数组删除项的数组。可实现删除Array.splice(0,1)、插入Array.splice(1,0,"red","blue")、替换Array.splice(1,1,"red","blue")操作。
indexOf()从前往后查找,lastIndexOf()从后往前查找,接收要查找的项和表示查找起点位置的索引。
every(),对数组中每项运行给定函数,每一项返回true则返回true。
filter(),对数组中每项运行给定函数,返回true项组成的数组。
forEach(),对数组中每项运行给定函数。
map(),对数组中每项运行给定函数,返回调用结果组成的数组。
some(),对数组中每项运行给定函数,如果有任一项返回true则返回true。
reduce()从前往后,reduceRight()从后往前,迭代数组中所有项,返回最终值。
5.3 Date类型
Date()
Date.parse()
Date.UTC()
Date.now()
getTime()
setTime()
5.4 RegExp类型
var expression=/pattern/flags;正则表达式字面量。
元字符,([{^$|)?*+.]}在正则表达式中具有特殊用途,因此字符串中出现时必须使用\转义。
var expression=new RegExp("[bc]at","i");RegExp构造函数。
5.5 Function类型
函数有以下三种定义:
1、函数声明function sum(num1,num2){//函数体}
2、函数表达式var sum=function(num1,num2){//函数体};
3、Function构造函数var sum=new Function("num1","num2","函数体");(不推荐)
解析器会率先读取函数声明,并使其在执行任何代码前可用;函数表达式必须等到解析器执行到它所在的代码才执行。
要访问函数的指针而不是执行函数,必须去掉函数名后面的圆括号。
arguments主要用途数保存函数参数,callee属性是一个指针,指向拥有这个arguments对象的函数。函数中如要调用函数本身,可以使用arguments.callee()保证在更换函数名的情况下正常完成递归调用。
this引用的是函数据以执行的环境对象。
函数名仅仅是一个包含指针的变量而已。
caller属性保存着调用当前函数的函数引用,如果是在全局作用域中调用当前函数,值为null。如function outer(){innder();}因为outer()调用了inner(),所有inner.caller指向outer(),返回outer()的源代码。
出于安全性考虑,arguments.caller在严格模式下报错,非严格模式下始终返回undefined。
函数的length属性表示函数希望接收的命名参数的个数。
prototype保存着引用类型所有实例方法。
apply()和call()在特定的作用域中调用函数。apply()接收this和参数数组(可使用arguments)。call()接收this和逐个列出的参数数组。它们能够扩充函数作用域。
bind()创建函数一个函数实例,其this值会被绑定到传给bind()函数的值。
5.6 基本包装类型
三种基本包装类型:Boolean、Number、String。基本类型值可以被当做对象来访问。操作基本类型值的语句一旦执行完毕,就会立即销毁新创建的包装对象。
toFixed(),按照指定的小数位返回数值的字符串表示。
toExponential(),返回以指数表示法表示的数值的字符串形式。
toPrecision(),表示某个数值最适合的格式。
chartAt(),接收基于0的字符位置。返回给定位置的那个单字符字符串。
chartCodeAt(),接收基于0的字符位置。返回给定位置的字符的字符编码。
substr(),接收字符串开始的位置和返回字符串的个数。传入负值时,第一个参数加上字符串长度,第二个参数转换为0。
substring(),接收字符串开始的位置和字符串最后一个字符后面的位置。传入负值时,会把第二个参数转换为0,将较小数作为开始位置,较大数作为结束位置。
trim(),创建一个字符串副本,删除前置及后缀的所有空格。
toLowerCase()、toLocaleLowerCase()、toUpperCase()、toLocaleUpperCase()字符串大小写转换。
match(),接收一个参数,正则表达式或RegExp对象。返回数组,数组第一项是与整个模式匹配的字符串,之后的每一项保存着与正则表达式中的捕获组匹配的字符串。
search(),接收由字符串或RegExp对象指定的一个正则表达式,返回字符串中第一个匹配项的索引,没有找到匹配项返回-1。
replace(),接收两个参数,第一个参数是一个RegExp对象或字符串,第二个参数是字符串或者函数。如果第一个参数是字符串,那么只会替换第一个子字符串;要替换所有字符串,则必须提供正则表达式,且指定g标志。返回替换后的字符串。
split(),基于指定的分隔符将一个字符串分割成多个子字符串,并保存为一个数组。第二个参数指定数组大小。
localeCompare(),比较两个字符串,返回负数(小于)、0(等于)、正数(大于)。
fromCharCode(),接收一或多个字符编码,转换成字符串。
5.7 单体内置对象
encodeURI()、 encodeURIComponent()对URI进行编码。前者用于整个URI,不会对本身属于URI的字符进行编码,如:/?#等。后者用于URI某一段,会对发现的任何非标准字符进行编码。
decodeURI()、 decodeURIComponent()对以上方法编码后的字符进行解码。
eval(),接收要执行的javascript字符串。eval()的任何变量或函数只在执行到该位置时创建。警惕使用eval()创建执行用户输入数据的代码。
Math.min()、Math.max(),确定一组数值中的最小最大值。
Math.floor(Math.random()*可能值的总数+第一个可能值),可以从某个范围获取某个值。
selectFrom(),接收两个参数,应该返回的最小值和最大值。返回范围内的某个值。
第6章 面向对象的程序设计
6.1 理解对象
ES中有两种属性:数据属性、访问器属性。
数据属性有4个描述其行为的特性:[[Configurable]]可配置,能否通过delete删除属性、重新定义属性、修改为访问器属性,默认true;[[Enumerable]]可枚举,能否通过for-in循环返回属性,默认true;[[Writable]]可写,默认true;[[Value]]属性值,默认undefined。
一旦把属性定义为不可配置的,就不能再变回可配置的了。
Object.defineProperty()修改特性属性,接收三个参数:属性所在的对象、属性的名字、描述符对象(可多个)。
在调用Object.defineProperty()时,如不指定,configurable、enumerable、writable特性默认值false。
Object.getOwnPropertyDescriptor()取得给定属性的描述符,接收两个参数:属性所在的对象、要读取其描述符的属性。,默认true;[[Enumerable]]可枚举,能否通过for-in循环返回属性,默认true;[[get]]读取属性时调用的函数,默认undefined;[[set]]写入属性时调用的函数,默认undefined。
属性前加_,表示只能通过对象方法访问。
只指定getter意味着属性不能写。
Object.defineProperties()通过描述符一次定义多个属性。接收两个对象参数:要添加和修改其属性的对象、对象的属性与第一个对象中要添加或修改的属性一一对应。
Object.getOwnPropertyDescriptor()取得给定属性的描述符,接收两个参数:属性所在的对象、要读取其描述符的属性名称。
6.2 创建对象
工厂模式,用函数来封装以特定接口创建对象的细节,如
function createPerson(name,age,job){
var o=new Object();
o.name=name;
o.sayName=function(){
alter(this.name);
};
return o;
}
构造函数模式,创建自定义构造函数,定义自定义对象类型的属性和方法,构造函数应以大写字母开头,非构造函数应以小写字母开头。如
function Person(name,age,job){
this.name=name;
this.sayName=function(){
alert(this.name);
};
}
原型模式,prototype就是通过调用构造函数创建的对象实例的原型对象,可以让所有对象实例共享它所包含的属性和方法。如
function Person(){
}
Person.prototype.name="Nicholas";
Person.prototype.sayName=function(){
alert(this.name);
};
更简单的原型语法
function Person(){
}
Person.prototype={
name:"Nicholas",
sayName:function(){
alert(this.name);
}
};
默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。
isPrototypeOf(),如果[[prototype]]指向调用isPrototypeOf()方法的对象,那么这个方法就返回true。
Object.getPrototypeOf()返回[[prototype]]的值。
每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从对象实例本身开始。如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。如果在原型对象中找到了这个属性,则返回该属性的值。
不能通过对象实例重写原型中的值,当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性。
delete操作符可以完全删除实例属性。
hasOwnProperty()方法可以检测一个属性是存在于实例中还是原型中,存在于对象实例中时返回true。
单独使用in操作符会在通过对象能够访问给定属性时返回true。
Object.keys()可以取得对象上所有可枚举的实例属性,接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。
Object.getOwnPropertyNames()可以得到所有实例属性。
Object.defineProperty()重设构造函数constructor属性。
重写原型对象切断了现有原型与任何之前已经存在的对象实例之间的联系。
创建自定义类型最常见方式,是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。
动态原型模式,把所有信息都封装在构造函数中,通过检查某个应该存在的方法是否有效,来决定是否需要初始化原型。
寄生构造函数模式,可以在特殊情况下用来为对象创建构造函数。基本思想是创建一个函数,作用仅为封装创建对象的代码,然后再返回新创建的对象。构造函数在不返回值的情况下,默认返回新对象实例。返回的对象与构造函数或者与构造函数的原型属性之间没有关系。
稳妥构造函数模式,稳妥对象指的是没有公共属性,而且其方法也不引用this的对象,适合在安全环境(禁用this和new)和防止数据被其他应用程序改动时使用。
6.3继承
原型链作为继承的主要方法,是利用原型让一个引用类型继承另一个引用类型的属性和方法。如SubType.prototype=new SuperType();
给原型添加方法的代码一定要放在替换原型的语句之后。通过原型链实现继承时,不能使用对象字面量创建原型方法。
借用构造函数,解决原型中包含引用类型值所带来的问题,通过在子类型构造函数的内部调用超类型构造函数。可以在子类型构造函数中向超类型构造函数传递参数。
组合继承,将原型链和借用构造函数的技术组合到一起。使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承。缺点是调用两次超类型构造函数:一次在创建子类型原型的时候,一次在子类型构造函数内部。
原型式继承,借助原型可以基于已有的对象创建新对象,不必因此创建自定义类型。必须有一个对象可以作为另一个对象的基础。
寄生式继承,创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。
寄生组合式继承,通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上是使用寄生式继承来继承超类型的原型,再将结果指定给子类型的原型。
第7章 函数表达式
函数声明提升,在执行代码前会先读取函数声明。
匿名函数的name属性是空字符串。把函数当成值来使用的情况下,都可以使用匿名函数。
函数表达式在使用前必须先赋值。
7.1 递归
递归函数,一个函数通过名字调用自身。调用自身时可以使用arguments.callee替代,严格模式下可以使用命名函数表达式来达成同样效果。
7.2 闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包常见方式是在一个函数内部创建另一个函数。
将函数赋值给null可以解除匿名函数的使用。
作用域链的副作用,闭包只能取得包含函数中任何变量的最后一个值。可以通过创建另一个匿名函数强制让闭包的行为符合预期。
匿名函数的执行环境具有全局性,因此this对象通常指向window。把外部作用域中的this对象保存在一个闭包能够访问的变量里,就可以让闭包访问该对象。
如果闭包作用域链中保存html元素,则该元素无法销毁。闭包会引用包含函数的整个活动对象,需要将保存着html的变量设置为null解除引用。
7.3 模仿块级作用域
匿名函数可以模仿块级作用域(私有作用域),让变量只存在于块级作用域内。如
(function(){
//块级作用域
})();
JavaScript将function关键字当作一个函数声明的开始,函数声明后面不能跟圆括号,而函数表达式后面可以跟圆括号,因此要将函数声明转换成函数表达式。
7.4 私有变量
任何在函数中定义的变量,都可以认为是私有变量。私有变量包括函数参数、局部变量、函数内部定义的其他函数。
特权方法,如果在函数内部创建一个闭包,闭包通过自己的作用域也可以访问这些变量。
利用私有和特权成员,可以隐藏那些不应该被直接修改的数据。
利用原型定义特权方法,访问到的属性是静态的、由所有实例贡献的。
模块模式,为单例创建私有变量和特权方法。单例指的是只有一个实例的对象。如果必须创建一个对象并以某些数据对其进行初始化,同时还要公开一些能够访问这些私有数据的方法,就可以使用模块模式。
在返回对象前加入对其增强的代码,适用于单例必须是某种类型的实例,还必须添加某些属性或方法的情况。