第五章 引入类型

来源:互联网 发布:中国老龄化数据 编辑:程序博客网 时间:2024/04/28 00:53

《javascript 高级程序设计》笔记

引用类型是一种数据结构,用于将数据功能组织在一起。(类似于类,但他不具备传统的面向对象语言所支持的类和接口等基本结构)

引用类型也被称为对象定义,因为它们描述的是一类对象所具有的属性方法

引用类型值(对象)是引用类型的一个实例

    var person=new Object(); //新对象是使用new操作符跟一个构造函数来创建的

5.1 Object 类型

大多数引用类型值都是Object类型的实例;而且,Object也是ECMAScript中使用最多的类型。

创建Object实例的两种方法:

    //第一种是使用new操作符跟Object构造函数    var person=new Object();    person.name="Nicholas";    person.age=29;    //第二种是对象字面量(它是对象定义的一种更简单形式)    var person={        name : "Nicholas",        age : 29, //这里使用逗号,容易导致IE7以上版本产生错误        5 : true //数值属性会自动转换为字符串    };        //第三种使用对象字面量时,如果花括号留空,则可以定义只包含默认属性和方法的对象    var person={};    person.name="Nicholas";    person.age=29;
对象字面量是面向函数传递大量可选参数的首选方法,开发人员更加青眯鱼字面量语法

注:对象字面量传递参数的模式适合需要向函数传入大量可选参数的情形。一般来讲,命名参数虽然容易处理,但在多个可选参数的情况下会显得不够灵活。最好的做法是对那些必须值使用命名参数,而使用对象字面量来封装多个可选参数。

访问对象的两种方法:

    //第一种使用点表示法    alert(person.name);    //第二种使用方括号    alert(person["name"]);    //从功能上讲两种方法没有任何区别。但方括号语法的主要优势是通过变量来访问属性,使用属性名或关键字保留子、空格也可以使用方括号表示    var propertyName="Nicholas";    alert(person[propertyName]);        person["first Name"]="Nicholas";
除了必须使用变量来访问属性,否则建议使用点

5.2 Array 类型

ECMAScript数组的每一项可以保存任何类型的数据(第一项未知用来保存字符串,第二项保存数字,第三系保存对象,以此类推),ECMAScript数组的大小是可以动态调整的,即可以随着数据的项目自动增长以容纳新数据。

创建数组的基本方法:

    //第一种Array 构造函数    var colors=new Array();    var colors=Array(); // 可以省略new    //第二种预先知道数组要保存的项目量,可以给构造函数传递该数量,而该数量自动变成length属性的值    var colors=new Array(20);    //第三种Array构造函数传递数组中应该包含的项    var colors=new Array("red","yellow","blue");    //构造函数能传递一个值,但传递的是数值,则会按照该数值创建包含给定项的赎罪;而如果传递的是其他类型参数,则会创建包含那个值的一个数组    var colors = new Array(3); //包含三项的数组    var colors = new Array("red"); //创建一个包含1项,即字符串"red"的数组        //数组字面量由一堆包含数组项的方括号表示,多个数组项之间以逗号隔开    var colors=["red","yellow","blue"];  //创建一个包含3个字符串的数组    var name=[]; //创建一个空数组    var values=[1,2,]; //创建两项或三项的数组(bug)    var options=[,,,,]; //创建四项或五项数组(bug)    //注:在IE8以以前的版本会出现bug,values、options会包含三项和五项的数组,分别是1、2和undefined数组
方括号中的索引表示要访问的值。如果索引小于数组中的项,则返回对应的值。如果设置某个值的索引超过了数组现有的项,数组就会自动增加索引的长度
    var colors=["red","yellow","blue"];    alert(colors[0]); //red;    alert(colors); //red,yellow,blue    colors[1]="black";    colors[2]="brown";    alert(colors); //red,black,brown    colors.length=4; //小于项目值,自动增加一个项目    alert(colors[3]); //undefined    alert(colors); //red,black,brown,    colors.length=2; //小于项目数,自动删除    alert(colors); //red,black    //利用length属性可以方便的在数组末尾添加新项,由于数组最后一项的索引始终是length-1,即下一项的值就是length    colors[colors.length]="yellow";    colors[colors.length]="orange";    alert(colors); //red,black,yellow,orange    //当把一个值超过当前数组大小的位置时,数组就会重新计算其长度值,即长度值等于最后一项的索引加1    colors[99]="black";    alert(colors.length); //100

5.2.1 检查数组

    //instanceof检查某个对象是否是数组,但存在问题,它假定只有一个全局变量的环境    if(value instanceof Array){        //对数组执行某些操作    }    //如果网页包含多个框架,实际存在连个以上的全局执行环境。ECMAScript5 新增了Array.isArray()方法。这个方法的最终确定某个值到底是不是数组,而不管它是在哪个全局执行环境中创建的    if(Array.isArray(value)){        //对数组执行某些操作    }    //The Array.isArray() determines whether the passed value is an Array.true if the object is an Array; Otherwise,false.    //all following calls return true    Array.isArray([]) ;    Array.isArray([1]);    Array.isArray(new Array());    //Litter know fact: Array prototype itself is an array:    Array.isArray(Array.prototype);    //all following calls return false    Array.isArray();    Array.isArray({});    Array.isArray(null);    Array.isArray(undefined);    Array.isArray(17);    Array.isArray('Array');    Array.isArray(false);    Array.isArray({__proto__: Array.prototype});

5.2.2 转换方法

toLocaleString() 方法(把数组转为本地字符串) arrayObject.toLocaleString() 返回本地字符串表示好

toString() 方法 (把数组转换为字符串)arrayObject.toString() 返回值 arrayObject 的字符串表示,返回值与没有参数的join() 返回的字符串一样

valueOf() 方法返回Array 对象的原始值 (通常由javascript在后台自动调用) arrayObject.valueOf()

    var colors=["red","yellow","blue"];    alert(colors); //red,yellow,blue(alert要接收字符串参数,所以它会在后台调用toString()方法)    alert(colors.toString()); //red,yellow,blue    alert(colors.valueOf()); //red,yellow,blue    alert(colors.toLocaleString()); //red,yellow,blue

toLocaleString() 方法经常也返回与 toString() valueOf()方法相同的值,但也不总是如此总是如此。

    var person1 = {        toLocaleString : function () {            return "Nicholas";        },        toString : function () {            return "Nicholas";        }    };    var person2 = {        toLocaleString : function () {            return "Grigorios";        },        toString : function () {            return "Greg";        }    };    var people = [person1, person2];    alert(people); //Nicholas,Greg(与toString相同)    alert(people.toString()); //Nicholas,Greg    alert(people.toLocaleString()); //Nicholas,Grigorios
join() 方法用于把数组中的所有元素放入一个字符串

    var arr = new Array(3)    arr[0] = "George"    arr[1]="John"    arr[2]="Thomas"    document.write(arr.join(".")+"<br />"); //George.John.Thomas    document.write(arr.join("|")); //George|John|Thomas

5.2.3 栈方法

栈是一种LIFO(Last-In-First-Out,弹出)的数据结构,也就是说最新添加的项最早被移除。而栈中项的插入(叫做推入)和移除(叫弹出),只发生在一个位置---栈的顶部。ECMAScript为数据专门提供了push() 和pop() 方法

push() 方法可以接收任意数量的参数,把它们逐个添加数组末尾并返回修改后数组的长度

pop() 方法则从数组末尾移除最后一项,减少数组length 值,然后返回移除的项。

    var colors = new Array();    var count = colors.push("red","green");    alert(count); //2    count = colors.push("yellow");    alert(count); //3    alert(colors); //red,green,yellow    count = colors.pop();    alert(count); //yellow    alert(colors); //red,green    colors[4]="black";    colors.push("brown");    alert(colors.length); //6    alert(colors); //red,green,,,black,brown    count=colors.pop();    alert(count); //brown

5.2.4 队列方法

栈的数据的访问规则是LIFO(后进先出),而队列的访问规则是FIFO (First-In-First-Out,先进先出)。队列在列表的末端添加项,从列表的前端移除项。

shift() 方法它能够移除数组中的第一个项并返该项,同时将数组长度减1。 arrayObject.shit()

结合使用shift() 和push() 方法,可以像队列一样使用数组

    var colors= new Array();    var count = colors.push("red","green");    alert(count); //2    count = colors.push("black");    alert(colors); //red,green,black    var item = colors.shift();    alert(item); //red    alert(colors.length); //2

unshift()shift()的用途相反,它能在数组前端添加任意个项并返回新数组的长度。与pop() 方法同时使用,能从反方向来模拟队列(队列前端添加,队列末端删除)

    var colors=new Array();    var count=colors.unshift("red","yellow","green");    alert(count); //3    count=colors.pop();    alert(count);//green
注:IE7及更早版本,unshift() 方法总是返回underfined 而不是数组长度

5.2.5 重排序方法

reverse() 方法颠倒数组中元素的顺序 arrayObject.reverse()

注:该方法会改变原来的数组,而不回创建新的数组。

    var arr=new Array("Tom","Alice","Thomas");    document.write(arr+"<br />"); //Tom,Alice,Thomas    document.write(arr.reverse()+"<br />"); //Thomas,Alice,Tom    var arr1=new Array(2,1,3,4,7);    document.write(arr1+"<br />"); //2,1,3,4,7    document.write(arr1.reverse()+"<br />"); //7,4,3,1,2


sort() 方法按升序排列数组项 --- 即最小的值位于最前面。    arrayObject.sort(sortby)     返回值 --- 对数组的引用。

注:数组在原数组上进行排序,不生成副本
如果调用该方法没有使用参数,将按字母顺序对数组中的元素进行排序,更精确一点,是按照字符编码的顺序进行排序。sort() 方法会调用每个数组项的 toString() 转型方法,然后表得到的字符串,以确定如何排序。(即使数组中的每一项都是数组,sort() 方法比较的也是字符串)

    var arr=new Array("Tom","Alice","Thomas");    document.write(arr+"<br />"); //Tom,Alice,Thomas    document.write(arr.sort()+"<br />"); //Alice,Thomas,Tom    var arr1=new Array(2,1,3,4,7,10,11,22);    document.write(arr1+"<br />"); //2,1,3,4,7,10,11,22    document.write(arr1.sort()+"<br />"); //1,10,11,2,22,3,4,7    var arr2=new Array(2,1,3,4,7,"red","yellow",10,11,22);    document.write(arr2+"<br />"); //2,1,3,4,7,red,yellow,10,11,22    document.write(arr2.sort()+"<br />"); //1,10,11,2,22,3,4,7,red,yellow

注:虽然数值5虽然小于10,但在进行字符串比较时,“10”则位于“5”的前面。

如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。

若 a 小于 b ,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值

若 a 等于 b ,则返回0

若 a 大于 b ,则返回一个大于 0 的值

    function compare(a,b) {        if ( a > b) {            return 1;        }else if (a <b ){            return -1;        }else {            return 0;        }    }    var values=[10,22,3,4,11,2];    values.sort(compare);    document.write(values+"<br />"); //2,3,4,10,11,22    function sortNum(a,b) {        return a-b;    }    var arr=[12,33,22,1,55,3];    arr.sort(sortNum);    document.write(arr); //1,3,12,22,33,55

5.2.6 操作方法

concat() 方法可以基于当前数组中的所有项创建一个新数组。先创建当前数组的副本,然后接收的参数添加到这个副本的末尾,最后返回新创建的数组。在没有给concat() 方法传递参数的情况下,它只是复制当前数组并返回副本

    var colors=["red","yellow","blue"];    var colors1=colors.concat("black","orange",["green","pink"]);    alert(colors); //red,yellow,blue    alert(colors1); //red,yellow,blue,black,orange,green,pink
slice() 方法可以接受一或两个参数,即要返回项的初始和结束为止。只有一个参数的情况下,slice() 返回从该参数指定位置开始到当前数组末尾的所有项。

    var colors=["red","yellow","blue","pink","green"];    alert(colors.slice(1)); //yellow,blue,pink,green    alert(colors.slice(1,3)); //yellow,blue    alert(colors.slice(-1)); //green    alert(colors.slice(-3,-1)); //blue,pink    alert(colors.slice(3,1)); //如果结束位置小于初始位置,则返回空数组
splice() 方法的主要用途是向数组中部插入添加、删除和替换项

注:该方法会改变原始数值

    // 删除 --- 制定2个参数,要删除的第一个项的位置和要删除的项数    var colors = ["red","blue","orange"];    var removed = colors.splice(1,1); //下标1的位置开始,删除1项,返回删除项    alert(colors); //red,orange    alert(removed); //blue    // 插入 --- 可以向指定位置插入任意数量的项,只需提供3个参数    removed = colors.splice(1,0,"yellow","black"); //位置1开始,删除0个项目,添加两个数值    alert(colors); //red,yellow,black,orange    alert(removed); //没有删除项,返回空值    // 替换 --- 指定位置插入任意数量的项,且同时删除任意数量的项,只需指定3个参数    removed = colors.splice(1,2,"pink","black");    alert(colors); //red,pink,black,orange    alert(removed); //yellow,black

5.2.7 位置方法

indexOf() 方法从数组的开头(位置0)开始向后查找

 lastIndexOf() 方法则从数组的末尾开始向前查找

注:这两个方法都返回要查找的项在数组中的位置,或者在没有的情况下返回 -1。

    var numbers = [1,2,3,4,5,4,3,2,1];    alert(numbers.indexOf(3)); //2    alert(numbers.lastIndexOf(3)); //6    alert(numbers.indexOf(3,3)); //6    alert(numbers.lastIndexOf(3,4)); //2

5.2.8 迭代方法

ECMAScript5 为数组提供五个迭代方法

    // every()方法 --- 数组中的每一项运行给定函数。如果每一项都返回true,则返回true    // some() 方法 --- 只要传入的函数对数组中的某一项返回true,就会返回true    // every() / some() 方法不回对空元素进行检测,不回改变原始数组    var numbers = [1,2,3,4,5,6,5,4,3,2,1];    var everyResult = numbers.every(function (item,index,array) {        return (item > 2);    });    alert(everyResult);  //false    var someResult = numbers.some(function (item,index,array) {        return (item >2);    })    alert(someResult); //true    // filter() 函数 --- 它利用指定的函数确定是否在返回的数组中包含某一项    // filter() 方法创造一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素    // filter() 对查找符合某些条件的所有数组非常有用    var filterResult = numbers.filter(function (item,index,array) {        return (item >2 );    });    alert(filterResult); //3,4,5,6,5,4,3    // map() 方法 --- 返回一个新数组,数组中的元素为元素数组元素调用函数处理后的值    var mapResult = numbers.map(function (item,index,array) {        return (item*2); //每一项都乘以2    })    alert(mapResult); //2,4,6,8,10,12,10,8,6,4,2    //forEach --- 对数组中的每一项传入函数    var numResult = numbers.forEach(function (item,index,array) {        //执行某些操作    })

5.2.9 归并方法

ECMAScript5 新增了两个归并方法:reduce() 和 reduceRight() 

这两个方法都会迭代数组的所有项,然后构建一个最终返回的值。reduce从第一项开始,reduceRight从最后一项开始

    //接收4个参数:前一个值、当前值、项的索引和数组对象    var values = [1,2,3,4,5,6,7]    var sum =values.reduce(function (prev,cur,index,array) {        return prev+cur;    })    alert(sum); //28

5.3 Date 类型

Date 类型使用自UTC ( Coordinated Universal Time , 国际协调时间) 1970年1月1日午夜起至该日期止经过的毫秒数来保存日起
var now = new Date(); //新创建的对象自动获得当前日期和时间

想根据特定的日期和时间创建日期对象,必须传入表示该日期的毫秒数(即从UTC 时间1970年1月1日午夜起至该日期经过的毫秒书)。

ESMAScript 提供了两种方法:Date.parse() 和 Date.UTC()

    //parse() 方法可以解析一个日期时间字符串,并返回1970年1月1日午夜距离该时间的毫秒数    var tParse = Date.parse("Jan 1 2017");//    var tParse = new Date("Jan 1 2017"); Date.parse() = new Date()    document.write("It's been: "+tParse+" years from 1970/1/1");    document.write(" to 2017/01/2"+"<br />");    //It's been: 47.03470319634703 years from 1970/1/1 to 2017/01/2    // 如果传入Date.parse() 方法字符不能表达日期,那么返回NAN    //UTC() 方法根据世界时间返回 1970年1月1日 到指定日期的毫秒数    //Date.UTC() 的参数分别是年份、基于0的月份(一月是0,二月是1,以此类推)    var tUTC = Date.UTC(2017,0,1);    document.write("It's been: "+tUTC+ " years from 1970/1/1"+"<br />")    // UTC() 根据世界时间 Parse() 根据本地时间    var sub = (tUTC -tParse)/1000/60/60;    document.write(sub);//8 位于东八区    // ECMAScript5 添加了Date.now() 方法,返回表示调用了这个方法时的日期和时间的毫秒数    // 取得开始的时间    var start = Date.now(); = var start = +new Date();    // 调用函数    doSomething();    // 取得停止的时间    var stop = Date.now(), = var stop = +new Date();            result =stop-start;

5.3.1 继承的方法

toLocaleString() 方法会按照与浏览器设置的地区相适应的格式返回日期和时间。(大致意思格式包含AM 和PM,但不回包含时区信息,且因浏览器不同而显示不同)

toString() 方法通常返回带有时区信息的日期和时间

valueOf() 方法不返回字符串,而返回日期的毫秒数

5.4 RegExp 类型

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

pattern 属性规定用于验证输入字段的模式

注:pattern 属性使用与一下 <input> 类型:text, search, url, telephone, email 以及password

g: 表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立刻停止

i: 表示不区分大小写

m:表示多行

    // 匹配字符串中所有"at"的实例    var pattern = /at/g;    // 匹配第一个"bat" 或"cat" ,不区分大小写    var pattern = /[bc]at/i;    // 匹配所有以"at" 结尾的3个字符串组合,不区分大小写    var pattern = /.at/gi;    // 元字符都必须转义,包括( [ { \ ^ $ | ) ? * + . ] }    // 匹配第一个"bat" 或"cat" ,不区分大小写    var pattern = /\[bc\]at/i;    var pattern = /\.at/gi;

5.5 Function 类型

每个函数都是Function 类型的实例,而且都与其他引用类型一样具有属性方法。由于函数是对象,因此函数名实际上也是一个指向函数对象的指针,不回与某个函数绑定。
    // 两种方法一样    function sum(num1,num2) {        return num1+num2;    }    var sum=function (num1,num2) {        return num1+num2;    }    //这种方法不推荐    var sum=new Function("num1","num2","return num1+num2");
函数名仅仅是指向函数的指针

    function sum(num1,num2) {        return num2+num1;    }    alert(sum(10,20)); //30    var anotherSum = sum;    alert(anotherSum(10,20)); //30    sum = null;    alert(anotherSum(10,20)); //30
注:使用不带圆括号的函数名是访问函数指针,而非调用函数。

anotherSum 和 sum 都指向一个函数,因此anotherSum可以被调用并返回结果。即使sum设置为null,让它与函数“断绝关系”,也可以得到正常的anotherSum();

5.5.1 没有重载(深入理解)

重载:函数或者方法由相同的名称,但是参数列不同的情况,这样的同名不同参数或者方法之间,互称为重载函数或方法。javascript没有重载,只有覆盖。

    function addSomeNumber(num) {        return num+100;    }    function addSomeNumber(num) {        return num+200;    }    var result = addSomeNumber(100); //300

5.5.2 函数声明与函数表达式

函数声明:function foo() {}

函数表达式:var foo = function {}

解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问),至于函数表达式,则必须等到解析器执行到它所在的代码行。

5.5.3 作为值的函数

ECMAScript 中的函数名本身就是变量,所以函数也可以作为值使用。也就是说,不仅可以传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回

    function callSomeFunction(someFunction,someArgument) {        return someFunction(someArgument);    }    function add10(num) {        return num+10;    }    var result1 = callSomeFunction(add10,20);    alert(result1); //30    function getGreeting(name) {        return "Hello "+name;    }    var result2 = callSomeFunction(getGreeting,"Nicholas");    alert(result2); //Hello Nicholas
要访问函数的指针而不执行函数的话,必须去掉函数名后面那对括号。因此callSomeFunction() 是add10 和getGreeting,而不是执行后的结果。

一个函数可以包含另一个函数(极为有用的一种技术)

    function createComparisonFunction(propertypeName) {        return function (object1,object2) {            var value1=object1[propertypeName];            var value2=object2[propertypeName];            if(value1 > value2){                return 1;            }else if(value1 < value2){                return -1;            }else {                return 0;            }        }    }    var data = [{name:"Tom",age:20},{name:"Nicholas",age:30}];    data.sort(createComparisonFunction("name"));    alert(data[0].name); //Nicholas    data.sort(createComparisonFunction("age"));    alert(data[0].name); //Tom
内部函数接收到propertyName 参数后,它会使用方括号表示法来取得给定的属性值。

5.5.4 函数内部属性

函数内部,有两个特殊的对象:arguments 和 this

arguments 是一个类数组对象,包含着传入函数中的所有参数。虽然arguments 的主要用用途是保存函数参数。但这个对象还有一个callee的属性,指向拥有这个arguments对象的函数。

参数:可以传递0个,1个,...,n个参数,命名参数只是提供便利,但不是必须的。

callee 该属性是一个指针,指向拥有这个arguments 对象的函数

    function factorial(num) {        if(num<=1){            return 1;        }else{            return num * arguments.callee(num-1);        }    }    alert(factorial(5)); //120
this 引用的事函数执行的环境对象----或者也可以说是 this 值(当在网页的全局域中调用函数时,this 对象引用的就是window)
    window.color = " yellow ";    var o = { color: "red"};    function sayColor() {        alert(this.color); // yellow    }    sayColor();    o.sayColor = sayColor; //含有括号是传递值    o.sayColor(); //red

5.5.5 函数属性和方法

ECMAScript 中的函数是对象,因此函数也有属性和方法。每个函数都包含两个属性:length prototype 

length --- 表示函数希望接收的命名参数的个数

    function sayName(name) {        alert(name);    }    function sum(num1,num2) {        return num1+num2;    }    function sayHi() {        alert("hi")    }    alert(sayName.length); //1    alert(sum.length); //2    alert(sayHi.length); //0
对于ECMAScript 中的引用类型而言,prototype 是保存它们所有实例方法的真正所在 (ECMAScript 5 prototype)

每个函数都包含两个非继承而来的方法:apply() 和 call()

用途:特殊的作用域中调用函数,实际上等于设置函数体内this 对象的值

apply() 接收两个参数,一个是运行的作用域,另一个是参数数组

    function sum(num1,num2) {        return num1+num2;    }    function callSum1(num1,num2) {        return sum.apply(this,arguments);    }    function callSum2(num1,num2) {        return sum.apply(this,[num1,num2]);    }    alert(callSum1(10,20)); //30    alert(callSum2(20,20)); //40
注:在严格模式下,未指定环境而调用函数,则this 值不会转型为window。除非明确把函数加到某个对象后调用apply() 或 call() ,否则this 将是underfined

call() 方法与 apply() 方法的作用相同,它们的区别仅在接收参数的方式不同对于call() 方法而言,第一个参数是this值没有变化,变化的是其余参数直接传递给函数。换句话说,在使用call() 方法时,传递给函数的参数必须逐个举例出来。

    function sum(num1,num2) {        return num1+num2;    }    function callSum1(num1,num2) {        return sum.call(this,num1,num2);    }    alert(callSum1(10,20)); //30
apply() 和call() 强大之处在于扩展函数赖以运行的作用域
    window.color="yellow";    var o ={color:"red"};    function sayColor() {        alert(this.color);    }    sayColor(); //yellow    sayColor.call(this); //yellow    sayColor.call(window); //yellow    sayColor.call(o); //red
ECMAScript5 定义了一个bind()。这个方法会创建一个函数实例。
    window.color="red";    var o={ color: "blue"};    function sayColor() {        alert(this.color);    }    var objectsayColor=sayColor.bind(o);    objectsayColor(); //blue

5.6 基本包装类型






0 0
原创粉丝点击