JavaScript高级程序设计读书笔记5

第5章 引用类型

Object类型

  • 创建Object实例的方式有两种:
    1. new操作符后跟Object构造函数
    2. 对象字面量表示法
1
2
3
4
5
6
7
8
9
10
11
//第一种
var person=new Object();
person.name="Nick";
person.age=29;

//第二种
var person={
name:"Nick",
age:29
};
}
  • var person={}new Object()相同
  • 访问对象属性有两种方式:

    1. 点表示法 person.name
    2. 方括号语法 person["name"]
  • 方括号语法可以通过变量来访问属性,而且可以访问带有空格的属性。除非必须使用变量来访问属性,否则我们建议使用点表示法

Array类型

  • 数组的每一项可以保存任何类型的数据
  • Array数组的创建方式有两种:

    new方法,也可省略new var colors=new Array(3)
    字面量表示法。var colors=["red","blue","green"];

  • 构造函数传递值的方式有两种:

    传递数值,创建给定项数的数组
    var colors=new Array(3); //创建一个包含3项的数组
    传递其他类型的参数,会创建包含这个值的数组
    var names=new Array("Grey"); //创建一个包含1项,字符串是“Grey”的数组

  • 数组的length不是只读的,可以设置该属性,从数组的末尾移除项或向数组中添加项。

    1
    2
    3
    4
    5
    var colors=["red","blue","green"];
    colors.length=2;
    alert(colors[2]); //undefined
    colors.length=3;
    alert(colors[3]); //undefined
  • 添加项的方式:colors[colors.length]="black";

    检测数组

  • instanceof操作符不能应对两个以上不同的全局执行环境
  • Array.isArray(value)用于最终确定这个值是不是数组,而不管它是在哪个全局执行环境中创建的。
    1
    2
    3
    var colors=["red","blue","green"];
    alert(colors instanceof Array); //true
    alert(Array.isArray(colors)); //true

转换方法

  • 所有对象都具有toString()、valueOf()、toLocaleString()方法
  • valueOf()返回数组本身,toString()方法返回由每个值的字符串形式拼接而成的一个逗号分隔符的字符串
1
2
3
4
var colors=["red","blue","green"];
alert(colors.toString()); //red,blue,green
alert(colors.valueOf()); //red,blue,green
alert(colors); //red,blue,green
  • toLocaleString()与前两个方法的不同是:调用每一项的toLocaleString()方法
  • join()用作分隔符的字符串,返回包含所有数组项的字符串
  • 如果数组中的某一项的值是null或undefined,在join()、toString()、valueOf()、toLocaleString()方法返回的结果中以空字符串表示

栈与队列

  • 数组可以表现得像栈一样。栈(后进先出) push() pop()
  • 数组可以表现得像队列一样。队列(先进先出)push() shift()
  • push()都返回修改后的数组长度
  • pop()方法返回移除的项
  • shift()方法移除数组中的第一项并返回该项
  • unshift():数组前端添加任意个项并返回新数组的长度
  • 使用unshift()和pop()可以从相反方向模拟队列。
    1
    2
    3
    4
    5
    6
    7
    8
    var colors=new Array();
    var count=colors.unshift("red","green");
    alert(count); //2
    count=colors.unshift("black");
    alert(count); //3
    var item=colors.pop();
    alert(item); //green 这是green不是red
    alert(colors.length); //2

重排序方法

  • reverse()翻转数组项的顺序
  • sort()调用每个数组项的toString()方法,按升序排列。即使数组中是数值,比较的也是字符串

    1
    2
    3
    var values=[0,1,5,10,15];
    values.sort();
    alert(values); //0,1,10,15,5
  • sort()方法可以接受一个比较函数作为参数,改变以上问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function compare(value1,value2){
    if(value1<value2){
    return -1; //降序可以把这个改成1
    }else if(value1>value2){
    return 1; //降序可以把这个改成-1
    }else{
    return 0;
    }
    }

    var values=[0,1,5,10,15];
    values.sort(compare);
    alert(values); //0,1,5,10,15
  • 如果是数值类型的对象或valueof()是数值类型的对象,可以直接相减即可

    1
    2
    3
    function compare(value1,value2){
    return value1-value2; //升序,降序改为 value2-value1
    }

操作方法

  • concat()复制当前数组,将参数添加到复制的数组的尾部。
  • slice()接受返回项的起始和结束位置的参数,返回数组中不包括结束位置的项。传入的参数如果是负数,就用数组长度加上该数。slice()方法不会影响原始数组。
  • splice()的主要用途是向数组中插入项,但也有删除、插入、替换三种操作。splice(起始位置、要删除的项数、要插入的任意数量的项)

位置方法

  • indexOf()从头开始查找项,返回要查找项在数组中的位置。
  • lastindexOf()从末尾开始查找项,返回要查找项在数组中的位置。
  • 两个方法的查找都是严格相等的,和===一样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var numbers=[1,2,3,4,5,4,3,2,1];
    alert(numbers.indexOf(4)); //3
    alert(numbers.lastIndexOf(4)); //5

    alert(numbers.indexOf(4,4)); //5
    alert(numbers.lastIndexOf(4,4)); //3

    var person={name:"Nicholas"}; //person对象,有一个name属性
    var people=[{name:"Nicholas"}]; //people数组,含有一个{name:"Nocholas"}的对象

    var morePeople=[person]; //morePeople数组,含有一个person对象

    alert(people.indexOf(person)); //-1
    alert(morePeople.indexOf(person)); //0
  • 注意:people数组中的对象不是person,所以查不到。

  • 用==和===比较两个对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var a=new Object({name:"a"});
    var b=new Object({name:"a"}); //a和b指向两个对象
    alert(a===b); //false
    alert(a==b); //false

    var a=new Object({name:"a"}); //a和b指向同一个对象
    var b=a
    alert(a===b); //true
    alert(a==b); //true
  • 无论是用==还是===比较两个地址不同的对象,都是false。如果两个值指向同一个对象,则都是true

迭代方法

  • every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true
  • filter():对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组
  • forEach():对数组中的每一项运行给定函数,没有返回值。本质上与使用for循环迭代数组一样
  • map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
  • some():对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true

归并方法

  • reduce():迭代数组的所有项,向后遍历
  • reduceRight():向前遍历数组的所有项

Date类型

  • Date.parse()接收一个表示日期的字符串,返回相应日期的毫秒数
  • Date.UTC()同上,但是月份基于0开始

继承的方法

  • toLocalString()、toString()按照与浏览器设置的地区相适应的格式返回日期和时间
  • valueOf()不返回字符串

RegExp类型

  • 每个正则表达式都可带有一或多个标志,用以表明正则表达式行为

    g:全局模式
    i:不区分大小写模式
    m:表示多行模式

  • 正则表达式字面量始终会共享同一个RegExp实例,而使用构造函数创建的每一个新RegExp实例都是一个新实例

RegExp实例方法

  • 主要方法是exec():专门为捕获组而设计,返回包含第一个匹配项信息的数组。有两个属性:index表示匹配项在字符串中的位置,input表示应用正则表达式的字符串
  • test()方法,在模式与该参数匹配的情况下返回true,否则返回false

Function类型

  • 每个函数都是Function类型的实例,而且都与其他引用类型一样具有方法和属性。
  • 函数是对象,函数名是指针。因此,没有重载。
  • 使用不带圆括号的函数名是访问函数指针,而非调用函数
  • 三种定义函数的方式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //函数声明
    function sum(num1,num2){
    return num1+num2;
    }
    //函数表达式,注意最后一个分号
    var sum=function(num1,num2){
    return num1+num2;
    };
    //Function构造函数,不建议这样写
    var sum =new Function("num1","num2","return num1+num2");

函数声明与函数表达式

  • 解析器会率先读取函数声明,并使其在执行任何代码之前可用。因此如果使用函数表达式的方法定义函数,将函数表达式写在函数定义前面会报错

作为值的函数

  • 函数可以作为另一个函数的参数

    1
    2
    3
    function callSomeFunction(someFunction,someArgument){
    return someFunction(someArgument);
    }
  • 函数可以作为另一个函数的返回结果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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 data=[{name:"Zachary",age:28},{name:"Nicholas",age:29}];

    data.sort(createComparisonFunction("name")); //按照name属性排序
    alert(data[0].name); //Nicholas

    data.sort(createComparisonFunction("age")); //按照age属性排序
    alert(data[0].name); //Zachary

函数内部属性

  • 函数内部:arguments对象,callee属性,指向拥有这个arguments对象的函数。经典的阶乘函数

    1
    2
    3
    4
    5
    6
    7
    function factorial(num){
    if(num<=1){
    return 1;
    }else{
    return num*arguments.callee(num-1);
    }
    }
  • 函数内部:this对象,引用的是函数执行的环境对象

  • caller属性:调用当前函数的引用
  • 严格模式下,arguments.callee、arguments.caller访问出错,不能给函数的caller属性赋值。非严格模式下arguments.caller=undefined。

    函数的属性和方法

  • 每个函数都包含两个属性:length和prototype
  • length:函数希望接受的命名参数的个数
  • prototype:保存所有实例方法的真正所在,toString()和valueOf()保存在其名下。prototype属性不可枚举。
  • 每个函数都包含两个非继承而来的方法:apply()和call()。
  • apply(运行函数的作用域,参数数组或arguments对象) call(运行函数的作用域,参数逐个列举)
  • apply()和call()的作用:1.传递参数 2.扩充函数赖以运行的作用域
  • bind():创建一个函数的实例
  • 函数的toString()、valueOf()、toLocaleString()方法都只返回函数代码

基本包装类型

  • 3个特殊的引用类型:Boolean、Number、String
  • 具有的共同特征

    1. 每个包装类型都映射到同名的基本类型
    2. 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作
    3. 操作基本类型值的语句一旦执行完毕,就会立即销毁新创建的包装对象
  • 引用类型与基本包装类型的主要区别是对象的生存期:new操作符创建的引用类型的实例,在执行流离开当前作用域前都一直保存在内存中,自动创建的基本包装类型的对象,只存在于一行代码的执行瞬间,然后立即被销毁。

  • 使用new调用基本包装类型构造函数,与直接调用同名的转型函数是不一样的。
    1
    2
    3
    4
    5
    6
    var value="25";
    var number =Number(value); //转型函数
    alert(typeof number); //"number"

    var obj=new Number(value); //构造函数
    alert(typeof obj); //"object"

Boolean

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

    1
    2
    3
    var falseObject=new Boolean(false);
    var result=falseObject && true;
    alert(result); //true
  • 建议永不使用

    Number

  • toFixed():参数表示几位小数,小数表示
  • toExponential():参数表示几位小数,指数表示(e)
  • toPrecision():根据参数,自动选择最合适的数值表示格式
  • 建议永不使用

String

字符方法

  • charAt():参数是基于0的字符位置,返回字符。 也可以使用stringValue[]这样的形式。
  • carCodeAt():参数是基于0的字符位置,返回字符编码。

    字符串操作方法

  • concat():拼接字符串,对原字符串没有影响
  • slice(开始位置,结束位置):返回子字符串,有负数时与字符串的长度相加
  • substr(开始位置,返回的字符个数):返回子字符串,第一个负数参数加上字符串的长度,第二个负数参数转换为0
  • substring(开始位置,结束位置):返回子字符串,把手游的负值参数都转换为0

    字符串位置方法

  • index():从字符串的开头,搜索给定字符串
  • lastIndexOf():从字符串的末尾向前搜索子字符串,搜索给定字符串

    trim()方法

  • trim():创建字符串的副本,删除前置及后缀的所有空格,然后返回结果,对原字符串没有影响

字符串大小写转换

  • toLowerCase():转换成小写
  • toLocaleLowerCase():针对特定地区实现
  • toUpperCase():转换成大写
  • toLocaleUpperCase():针对特定地区实现

字符串的模式匹配方法

  • match():与exec()方法相同,参数是正则表达式或是RegExp对象,返回数组
  • search():参数是正则表达式或是RegExp对象,返回第一个匹配项的索引。
  • replace():替换。如果要替换所有的子字符串,需要制定全局g标志
  • split():基于制定的分隔符将一个字符串分割成多个字符串,并将结果放在数组中

localeCompare()方法

  • localeCompare():比较两个字符串。字符串在字母表中应该排在字符串参数之前,就返回一个负数,等于就返回0,之后就返回一个正数
  • 返回的数值取决于实现,而不一定是-1,0,1。

formCharCode()方法

  • formCharCode():接受一或多个字符编码,将它们转换成一个字符串

单体内置对象

  • 由ECMAScript实现提供的、不依赖于宿主环境的对象,这些对象在ECMAScriptz程序执行之前就已经存在了。也就是说,开发人员不必显式地实例化内置对象,因为它们已经实例化了
  • 内置对象:比如:Object、Array、String

Global对象

  • 不属于任何其他对象的属性和方法,都是它的属性和方法

URI编码方法

  • URI(Uniform Resource Identifiers):通用资源标识符
  • encodeURI():对整个URI编码,发送给浏览器
  • encodeURIComponent():主要用于对URI中的某一段进行编码,发送给浏览器
  • encodeURI()和encodeURIComponent()的区别:encodeURI()不会对本身属于URI的特殊字符进行编码,encodeURIComponent则会对它发现的任何非标准字符进行编码
  • 相对应的方法还有decodeURI()、decodeURIComponent()

eval()方法

  • 通过eval()执行的代码被认为是包含该次调用的执行环境的一部分,因此被执行的代码具有与该执行环境相同的作用域链。
  • 通过eval()执行的代码可以引用在包含环境中定义的变量
  • 严格模式下,外部访问不到eval()中创建的任何变量或函数

window对象

  • 访问Global对象有两种方法:
    1. window对象
    2. 返回this值取得Global对象
1
2
3
var global=function(){
return this;
}();

Math对象

min和max方法

  • 寻找数组中的最大最小值,可以使用apply()方法。关键在于把Math对象作为apply()的第一个参数,从而正确地设置this值。
    1
    2
    3
    var values=[1,2,3,4,5,6];
    var max=Math.max.apply(Math,values);
    alert(max);

舍入方法

  • Math.ceil():向上舍入
  • Math.floor():向下舍入
  • Math.round():标准舍入

random()方法

  • 值=Math.floor(Math.random()*可能值的总数+第一个可能的值)
    1
    2
    3
    4
    function selectForm(lowerValue,upperValue){
    var choices=upperValue-lowerValue+1;
    return Math.floor(Math.random()*choices+lowerValue);
    }