引用类型相似于Java中的类,但和传统的面向对象语言所支持的类和接口截然不同,本章介绍ECMAScript提供的原生引用类型。html
引用类型的值通常均被认为是Object类型的实例,Object类型也是ECMAScript中使用最多的类型。java
建立Object实例的方法有两种,第一种是使用new操做符后跟Object构造函数:node
var person = new Object(); person.name = "XXX"; person.age="22";
另外一种方式是使用对象字面量表示法:正则表达式
var person = { name: "XXX", age: 22 };
对参数的访问可使用点表示法,也能够是用方括号表示法。express
var name = person.name; var age = person["age"];
使用方括号的优势是方括号中的字符串能够用变量表示。数组
通常使用点表示法更直观一些。浏览器
hivar value = numbers.reduce(function(prev, cur, index, array){ var res = prev + cur; console.log(prev + " + " + cur + " = " + res); return res; }); console.log("result = " + value); /** 1 + 2 = 3 3 + 3 = 6 6 + 4 = 10 10 + 5 = 15 15 + 6 = 21 21 + 7 = 28 result = 28 */
建立数组的基本方式也有两种。第一种是使用Array构造函数:app
var colors = new Array(); //建立一个数组
var colors = new Array(3); //建立一个包含三个元素的数组
也能够想Array构造函数传递应该包含的项目dom
var colors = new Array("red", "blue", "green"); //建立一个包含三个元素的数组
以上两段代码中的new操做符能够省略。函数
第二种方法是使用数组字面量表示法。
var colors = ["red", "blue", "green"]; //建立一个包含三个字符串的数组 var names = []; //建立一个空数组 var values =[1, 2, ]; //不要这样,这样会差ungjianyige2或3个元素的数组 var options = [,,,,]; //不要这样,这样会建立一个5-6个元素的数组
数组的长度存放在数组对象的length属性中。
var colors = ["red", "blue", "green"]; console.log(colors.length); //3 colors[99] ="black"; console.log(colors.length); //100
检测一个数组对象是否是数组类型,可使用instanceof操做符,也可使用Array.isArray(value)方法。
Array的toString和toLocalString方法,首先调用各个元素的toString和toLocalString方法,而后用逗号拼接成字符串返回。
使用join方法可使用其余字符串拼接。
var colors = ["red", "blue", "green"];
console.log(colors.join("||")); //red||blue||green
console.log(colors.join()); //red,blue,green
Array还提供了栈和队列使用的方法。
栈使用push和pop方法,只在数组末尾进行操做。
队列使用push和shift方法,在队尾进队头出。队列还提供了unshift方法,在对头推入元素。
数组的反序使用reverse方法,将元素倒序排列。
默认状况是数组排序都是先调用各个元素的toString方法,而后对字符串进行排序。这样排列数值数组就会出现问题:
var array = [1,2,4,13,25]; var temp = array.sort(); console.log(array); //[ 1, 13, 2, 25, 4 ] console.log(temp); //[ 1, 13, 2, 25, 4 ]
sort方法能够接收一个比较函数做为参数,以便咱们指定哪一个值位于哪一个值前面。
var array = [1,2,4,13,25]; array.sort(compare); console.log(array); //[ 1, 2, 4, 13, 25 ] function compare(v1, v2){ return v1 - v2; }
concat方法将参数加入到当前数组,并返回增长后的数组。当前数组内容不变。
var array = [1,2,4,13,25]; var a2 = array.concat([9,4,[6,7,1]]); console.log(a2.length); //8 console.log(array.length); //5 console.log(a2); //[ 1, 2, 4, 13, 25, 9, 4, [ 6, 7, 1 ] ]
slice()方法接收一个或两个参数,返回子数组,第一个参数表示开始位置,第二个参数表示结束位置。 slice方法不影响原数组。
var array = [1,2,4,13,25]; var subArray = array.slice(2, 4); var subArray2 = array.slice(2); console.log(subArray); //[ 4, 13 ] console.log(subArray2); //[ 4, 13, 25 ]
splice()方法,能够用来删除、插入、替换。删除时,接收两个参数,第一个参数表示要删除的位置,第二个参数表示要删除的项数;插入时接收三个参数:起始位置、要删除的项数(0)和要插入的项。
var colors = ["red", "blue", "green"]; var removed = colors.splice(0, 1); console.log(colors); //[ 'blue', 'green' ] console.log(removed); //[ 'red' ] removed = colors.splice(1, 0, "yellow", "gray"); console.log(colors); //[ 'blue', 'yellow', 'gray', 'green' ] console.log(removed); //[] removed = colors.splice(1, 1, "red", "pink"); console.log(colors); //[ 'blue', 'red', 'pink', 'gray', 'green' ] console.log(removed); //[ 'yellow' ]
indexOf()方法和ilastIndexOf()方法,都接收两个参数:要查找的项和表示查找起点位置的索引(可选)。indexOf从头开始查找,lastIndexOf从末尾开始向前查找。
这两个方法返回要查找的项在数组中的位置,没有找到的状况下返回-1。比较过程当中使用的是全等操做符(===)。
数组的迭代方法有:
var numbers = [1, 2, 3, 4, 5, 6, 7]; var everyResult = numbers.every(function(item, index, array){ return (item > 2); }); console.log(everyResult); //false var someResult = numbers.some(function(item, index, array){ return (item > 2); }); console.log(someResult); //true
var numbers = [1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 1, 2]; var filterResult = numbers.filter(function(item, index, array){ return (item > 2); }); console.log(filterResult); //[ 3, 4, 5, 6, 7, 7, 6, 5, 4 ]
var numbers = [1, 2, 3, 4, 5, 6, 7]; var mapResult = numbers.map(function(item, index, array){ return (item * 2); }); console.log(mapResult); //[ 2, 4, 6, 8, 10, 12, 14 ]
ECMAScript5还提供了两个归并数组的方法:reduce()和reduceRight()函数,这两个函数都会迭代数组中全部的项,而后构建一个最终返回的值。其中reduce()从左向右逐个遍历,而reduceRight()从右向左逐个遍历。
两个方法都接收两个参数:一个在每一项上调用的函数(四个参数:前一个值、当前值、项的索引和数组对象),另外一个是做为归并基础的初始值(可选)。
函数返回的值会做为第一个参数自动传给下一个函数执行,第一次执行的时候,前一个值(第一个参数)是数组第一个元素,当前值(第二个参数)是数组第二个元素。
var numbers = [1, 2, 3, 4, 5, 6, 7]; var value = numbers.reduce(function(prev, cur, index, array){ var res = prev + cur; console.log(prev + " + " + cur + " = " + res); return res; }); console.log("result = " + value); /** 1 + 2 = 3 3 + 3 = 6 6 + 4 = 10 10 + 5 = 15 15 + 6 = 21 21 + 7 = 28 result = 28 */
ECMAScript中的Date类型是在早期Java中的java.util.Date类型的基础上构建的。为此,Date类型使用自UTC 1970年1月1日0时开始通过的毫秒数来保存日期。Date类型保存的日期可以精确到1970年1月1日以前或以后的285616年。
建立日期对象可使用new操做符,也能够用Date.now()返回当前的毫秒数(通常用于判断一段代码的执行时间,startTime endTime)。
var date = Date.now(); var date1 = new Date(Date.parse("2016-01-06")); var date2 = new Date(); console.log(date); //1452065871699 console.log(date1); //Wed Jan 06 2016 08:00:00 GMT+0800 (CST) (由于是东8时区因此是8点) console.log(date2); //Wed Jan 06 2016 15:37:51 GMT+0800 (CST)
ECMAScript经过RegExp类型来支持正则表达式。建立正则表达式也有两种方法,第一种是字面量表达式 var expression = /pattern/ flags; 其中,flag可取的值有三个:
模式中全部的元字符必须转义。须要转义的元字符有: ()[]{}\^$|?*+.
第二种建立正则表达式的方法是使用new操做符 var expression = new RegExp(pattern, flag); 。
var re = null, temp = null, i; for(i=0; i <10; i++){ re = /cat/g; temp = re.test("catastrophe"); console.log(temp); //true } temp = re.test("catophetast"); console.log(temp); //false for(i=0; i<10; i++){ re = new RegExp("cat", "g"); temp = re.test("catophetast"); console.log(temp); //true } temp = re.test("catophetast"); console.log(temp); //false
RegExp有下列属性,用于判断模式的信息。(这些属性实际上没什么用,由于你声明的时候已经设置了这些信息)
RegExp实例方法中主要的方法是exec(),该方法是专门为捕获组而设计的。exec()接收一个参数,即要应用模式的字符串,而后返回包含第一个匹配项信息的数组;或者在没有匹配性的时候返回null。
返回的虽然是Array实例,但包含两个额外的属性:index和input。其中index表示匹配项在字符串中的位置,而input表示应用正则表达式的字符串。
在数组中,第一项是与整个模式匹配的字符串,其余项是与模式中的捕获组匹配的字符串(若是模式中没有捕获组,则该数组中只包含一项)。
var text = "grandpa and mom and dad and baby"; var pattern = /mom( and dad( and baby)?)?/gi; var matches = pattern.exec(text); console.log(matches.index); //12 console.log(matches.input); //grandpa and mom and dad and baby console.log(matches); /* [ 'mom and dad and baby', ' and dad and baby', ' and baby', index: 12, input: 'grandpa and mom and dad and baby' ] */
RegExp中第二个方法是test(),它接收一个字符串参数,在模式与该参数匹配的状况下返回true,不然返回false。通常用于if语句。
var text = "010-6812-0917"; var pattern = /\d{3}-\d{4}/ if(pattern.test(text)){ console.log("The pattern was matched."); //The pattern was matched. }
ECMAScript中的函数其实是对象类型的实例,所以函数名实际上一个指向函数对象的指针,不会与某个函数绑定。所以下面两个函数声明的方式很相似。
function sum(num1, num2){ //函数声明 return num1 + num2; } var sum = function(num1, num2){ //函数表达式 return num1 + num2; }
区别在于解析器会率先读取函数声明,并使其在任何代码以前可用(能够访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被执行。
console.log(sum(5, 6)); //11 function sum(num1, num2){ return num1 + num2; }
console.log(sum(5, 6)); //11 var sum = function(num1, num2){ return num1 + num2; } /* TypeError: undefined is not a function at Object.<anonymous> (/home/zzl/Study/nodejs/studyjs/functionjs.js:1:75) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:902:3 */
另外,定义函数还有另外一种方法: var sum = new Function("num1", "num2", "return num1 + num2"); 。这种语法对于理解“函数是对象,函数名是指针”的概念却是很是直观,可是不推荐使用这种方式,由于解析器须要解析传入构造函数中的字符串,最后一个字符串被认为是函数体,前面的字符串都被认为是参数。
理解函数名是变量对与js相当重要,由于是变量,因此能够做为其余函数的参数或者返回值返回。
function createComparisonFunction(propertyName){ return function(object1, object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if(value1 < value2){ return -1; }else if(value1 > value2){ return 1; }else{ return 0; } } } var array = [{name:"zhou", age:18},{name:"liu", age:28}]; array.sort(createComparisonFunction("name")); console.log(array[0].name); //liu array.sort(createComparisonFunction("age")); console.log(array[0].name); //zhou
函数做为一个Function的类型,包含两个特殊的对象:arguments 和 this。
arguments是一个类数组的对象,包含着全部传入函数的参数。arguments 还有一个callee属性,该属性是一个指针,指向拥有这个arguments对象的函数。该指针对于递归调用尤为重要。
function factorial(num){ if(num <= 1){ return 1; }else{ //return num * factorial(num-1); return num * arguments.callee(num-1); } } temp = factorial; factorial = null; console.log(temp(4)); //24
函数内部另外一个特殊对象是this,其行为和Java大体相同。也就是说,this引用的是函数据以执行的环境对象。
ECMAScript 5也规范化了另外一个函数对象的属性:caller。该属性保存者调用当前函数的函数引用,若是是在全局做用域中调用当前函数,它的值返回null。在caller后加括号就至关于调用了outer函数,马上会引发栈溢出。
function outer(){ inner(); } function inner(){ console.log(inner.caller; //[Function: outer] console.log(arguments.callee.caller); //[Function: outer] } outer();
在严格模式下,caller 和 callee 都是不容许的,由于侵犯到了别的函数的空间。
ECMAScript中函数对象还有length 和 prototype 属性,其中length属性表示函数但愿接收的函数参数的个数。
对于引用类型而言,prototype属性是保存他们说有实例方法的所在。也就是说,对象的 toString() valueOf()等函数,其实是保存在prototype名下的,只不过是经过各自对象的实例访问罢了。在建立自定义引用类型以及实现继承时,prototype属性的做用是极为重要的。
每一个函数都包含两个非继承而来的方法:apply()和call()。这两个方法的用途都是在特定的做用域中调用函数,实际上等于设置函数体内this对象的值。
apply()方法接收两个参数:一个是在其中运行函数的做用域,另外一个是参数数组(能够是Array类型的实例,也能够是arguments对象)。才`
function sayHello(name){ console.log("Hello " + name + ". Your age is " + this.age); } var o = {age:28}; global.age = 15; console.log(this.age); //undefined console.log(age); //15 sayHello.call(this, "LiLei"); //Hello LiLei. Your age is undefined sayHello.call(o, "LiLy"); //Hello LiLy. Your age is 28 sayHello.apply(global, ["Polly"]); //Hello Polly. Your age is 15 sayHello.apply(o, ["Tom"]); //Hello Tom. Your age is 28
从上面的代码里能够得出,在nodejs中在全局函数中传this并非传递的global(相似于浏览器中的window对象)因此函数中调用this.age为undefined。
ECMAScript 5中还定义了bind()方法 用于绑定做用域。
function sayHello(name){ console.log("Hello " + name + ". Your age is " + this.age); } var o = {age:28}; global.age = 15; var sayHelloToObject = sayHello.bind(o); sayHelloToObject("HanMeimei"); //Hello HanMeimei. Your age is 28 sayHello.bind(o)("HanMeimei2"); //Hello HanMeimei2. Your age is 28
基本包装类型包括:Boolean、Number、String
每当读取一个基本类型值的时候,后台就会建立一个对应的基本包装类型对象,从而让咱们可以调用一些方法来操做这些数据。过程以下:
引用类型与基本包装类型的主要区别就是对象的生存期。使用new操做符建立的引用类型的实例,在执行流离开当前做用域以前都一直保存在内存中。
而自动建立的基本包装类型的对象,则之存在与一行代码的执行瞬间,而后当即被销毁。
Object构造函数也会像工厂方法同样,根据传入值的类型返回相应基本包装类型的实例。
var obj = new Object("lalala"); console.log(obj instanceof String); //true var str = "hello"; var strObj = new String("lilili"); var tempStrObj = String(str); console.log(typeof tempStrObj); //string console.log(typeof strObj); //object
通常来讲,不建议显示地建立基本包装类型的对象,在基本数据类型的变量上能够直接调用包装类型的方法。
Boolean类型 是与布尔值对应的引用类型。可是做为Boolean类型的对象,是用Object方式来判断真假的。
var booleanObje = new Boolean(false); if(booleanObje){ console.log("true"); }else{ console.log("false"); }
上面代码返回的true,因此建议永远不要使用Boolean对象。
Number类型 是与数字值对应的引用类型。
toFixed()方法会按照制定的小数位返回数值的字符串表示。按照四舍五入保留到小数点后某位。
var num = 5.12521212; console.log(num.toFixed(2)); //5.13
toExponential()方法返回以指数表示法表示的数值字符串形式。
var num = 123456.78 console.log(num.toExponential(2)); //1.23e+5
toPrecision()方法能够根据数值的大小判断返回固定大小的格式仍是科学表示法的形式的字符串。
var num = 99; console.log(num.toPrecision(1)); //1e+2 console.log(num.toPrecision(2)); //99 console.log(num.toPrecision(3)); //99.0
String类型 是字符串的对象包装类型。
String类型的每个实例都包含一个length属性,表示字符串中包含了多少个字符。
concat()方法用于将多个字符串拼接起来,返回拼接之后的新字符串,和字符串的(+)操做符同样。
substr()、substring()、slice()三个函数都是用来返回子字符串的,后两个方法是同样的,substr()方法若是有第二个参数,则表示子字符串的长度,其余两个的第二个参数表示结束位置后面的位置。
var str = "helloworld!"; console.log(str.substr(3)); //loworld! console.log(str.substring(3)); //loworld! console.log(str.slice(3)); //loworld! console.log(str.substr(3,5)); //lowor console.log(str.substring(3,5)); //lo console.log(str.slice(3,5)); //lo
模式匹配方法,match()方法(同RegExp的exec()方法),match()方法只接收一个参数,要么是个正则表达式,要么是个RegExp对象。
var text = "grandpa and mom and dad and baby"; var pattern = /mom( and dad( and baby)?)?/gi; var matches1 = text.match(pattern) var matches = pattern.exec(text); console.log(matches.index); //12 console.log(matches.input); //grandpa and mom and dad and baby console.log(matches); /* [ 'mom and dad and baby', ' and dad and baby', ' and baby', index: 12, input: 'grandpa and mom and dad and baby' ] */ console.log("==============================================="); console.log(matches1.index); //undefined console.log(matches1.input); //undefined console.log(matches1); //[ 'mom and dad and baby' ]
由上面的代码能够看出,match 和 exec 方法返回的值并不一致,exec 方法返回的信息更详尽而且有捕获组,而match没有捕获组的内容。
另外一个查找模式的方法是search()。参数也是正则表达式或RegExp对象,返回字符串中第一个匹配项的索引;若是没有找到匹配项,则返回-1.
var text = "cat, bat, sat, fat"; var reg = /at/g; var res; res = text.search(reg); console.log(res); //1 res = text.search(reg); console.log(res); //1
可见search 方法始终从字符串开头向后查找,即便指定了g也是如此。
replace()方法,用于简化替换子字符的操做,接受两个参数,第一个参数能够是一个RegExp 对象或者一个字符串,第二个参数能够是一个字符串或者函数。若是第一个参数是字符串,那么只会替换第一个子字符串。要想替换全部子字符串,惟一的办法就是提供一个正则表达式,并且要制定全局(g)标志。
var text = "cat, bat, sat, fat"; var result; result = text.replace(/.at/, "word"); console.log(result); //word, bat, sat, fat result = text.replace(/.at/g, "word"); console.log(result); //word, word, word, word
第二个参数是函数时,函数接受三个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串。
function htmlEscape(text){ return text.replace(/[<>"&]/g, function(match, pos, originalText){ switch(match){ case "<": return "<"; case ">": return ">"; case "&": return "&"; case "\"": return """; } }); } //<p class="test">Hello World!</p> console.log(htmlEscape("<p class=\"test\">Hello World!</p>"));
另外还有split()、indexOf()、trim()、charAt()等方法同Java,就不一一列举了。
Global对象,是ECMAScript中是做为一个终极的“兜底儿对象”,不属于任何其余对象的属性和方法,最终都是他的属性和方法,全部在全局做用于中定义的属性和函数,都是Global对象的属性。好比isNaN()、isFinite()、parseInt()、parseFloat()实际上都是Global 对象的方法。
encodeURI() 和 encodeURIComponent() 方法能够对URI进行编码,以便发送给浏览器。有效的URI中不能够包含某些字符,例如空格。这两个方法能够就URI进行编码,他们用特殊的UTF-8编码替换全部无效的字符,从而让浏览器可以接受和理解。
var uri = "http://www.baidu.com/illegal value.html#start"; console.log(encodeURI(uri)); //http://www.baidu.com/illegal%20value.html#start var temp = encodeURIComponent(uri); console.log(temp); //http%3A%2F%2Fwww.baidu.com%2Fillegal%20value.html%23start console.log(decodeURI(temp)); //http%3A%2F%2Fwww.baidu.com%2Fillegal value.html%23start console.log(decodeURIComponent(temp)); //http://www.baidu.com/illegal value.html#start
对应的解码的方法是decodeURI()、decodeURIComponent()。
eval()方法接受一个字符串,即要执行的ECMAScript字符串。
eval(console.log("hello")); //hello
ECMAScript没有指出如何直接访问Global对象,可是Web浏览器都是将这个全局对象做为window对象的一部分加以实现的。所以在全局做用于中生命的全部变量和函数,都成为window对象的属性。
Math对象,min()和max()方法用于肯定一组数值中的最小值和最大值。这两个方法均可以接受任意多个数值参数。
舍入方法:Math.ceil()向上舍入、Math.floor()向下舍入、Math.round()四舍五入。
random()方法返回大于0小于1的一个随机数。