Skip to content

Latest commit

 

History

History
444 lines (360 loc) · 18.3 KB

5. 引用类型.md

File metadata and controls

444 lines (360 loc) · 18.3 KB

引用类型的值(对象)是引用类型的一个实例,引用类型是一种数据结构

Object 类型

创建对象

创建 Object 实例的方式有两种:

  • 使用 new 操作符后跟 Object 构造函数 var person = new Object()

  • 使用对象字面量表示法

    var person = {
        name: "Ada",
        age: 28
    }
    

    其中属性名也可以使用字符串

    通过对象字面量定义对象时,实际上不会调用 Object 构造函数 最好的做法是对必需值使用命名参数,然后使用对象字面量封装多个可选参数。

访问对象的属性

alert(person.name);
alert(person["name"]); // 如果属性中包含会导致语法错误的字符(如空格),或者属性使用的是关键字或保留字,就需要使用方括号表示法

Array 类型

ECMAScript 数组的每一项可以保存任何类型的数值,并且数组大小可以动态调整,随着数据的增加自动增长

创建数组

  • 使用 Array 构造函数 var colors = new Array(); // new 可以省略
  • 使用数组字面量表示法 var colors = ["red", "blue", "green"]; // 不要在最后一项后面添加括号 使用数组字面量表示法时,也不会调用 Array 构造函数

数组的基本操作

colors[4] = "black";

  • 如果数组长度小于5,会将这个数组的长度增加到5,第五项值为 "black",其他项为 undefined
  • 如果数组长度大于5,会将这个数组的第五项的值修改为 "black"

数组的 length 属性不是只读的,可以通过修改这个属性向数组删除项或者添加新项

colors[colors.length] = "black"; //向数组最后增添值为 "black" 的新项

数组最多可容纳 4 294 967 295 个项,几乎能够满足任何编程需求了。

检测数组

if (value instanceof Array) {
    // 对数组进行操作
}

instanceof 操作符的问题在于,它假定只有一个全局环境,如果网页包含多个框架就会产生问题。

ES5 新增了 Array.isArray() 方法来确定某个值到底是不是数组。

if (Array.isArray(value)) {
    // 对数组进行操作
}

转换方法

  • toString():返回一个以逗号分隔数组每一项的字符串
  • valueOf():返回的是数组原始值
  • toLocaleString()
  • join():接受一个参数,以字符串形式传入分隔符,返回一个以分隔符分隔每一项的字符串,未传入值的话默认使用逗号

栈方法

ECMAScript 专门为数组提供了 push() 和 pop() 方法,用来实现类似栈的行为

队列方法

  • push():向数组末端添加项
  • shift():移除数组第一个项并将其返回
  • unshift():向数组前端添加项并返回新数组的长度

重排序方法

reverse()

反转数组顺序,返回排序后的数组

sort()

调用每一项的 toString() 方法,比较得到的字符串,然后返回排序后的数组

默认情况下升序排列,可以传入一个比较函数作为参数以指定比较方法

// 升序
function compare(value1, value2) {
    if (value1 < value2) {
        return -1;
    } else if (value1 > value2) {
        return 1;
    } else {
        return 0;
    }
}

// 降序
function compare(value1, value2) {
    if (value1 < value2) {
        return 1;
    } else if (value1 > value2) {
        return -1;
    } else {
        return 0;
    }
}

操作方法

concat()

为当前数组创建一个副本,将传入参数添加到它的末尾,返回该数组

slice()

第一个参数是起始位置,第二个参数是结束位置。该方法会获得从起始位置到结束位置(不包括结束位置的项)的所有项返回一个新数组。如果没有第二个参数,则一直返回到数组末尾。如果结束位置小于起始位置则返回一个空数组。

splice()

传入三个参数:起始位置,要操作的项数,新的项

  • 只有前两个参数则会执行删除操作
  • 第二项为 0 则会执行插入操作
  • 三个参数都有则会执行替换操作,插入项数不必与删除项数相等 该方法返回一个数组,包括从原始数组中删除的项(没有删除项则返回空数组)

位置方法

indexOf() 与 lastIndexOf()

比较参数与数组中每一项时使用全等比较,没找到时返回-1

迭代方法

每个方法接受两个参数:在每一项上调用的函数、运行函数的作用于对象(可选)

传入的函数接受三个参数:数组项的值、该项在数组中的位置、数组对象本身

arr.every(function(item, index, array))

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

归并方法

reduce() 与 reduceRight()

每个方法接受两个参数:在每一项上调用的函数、作为归并基础的初始值(可选)

传入的函数接受四个参数:前一个值、当前值、项的索引、数组对象

arr.reduce(function(prev, cur, index, array))

Date 类型

使用 UTC 时间 (Coordinated Universal Time 国际协调时间) 1970年1月1日零时开始经过的毫秒数

var now = new Date(); // 构造函数不传参情况下自动获取当前时间

  • Date.parse() 方法接受一个表示日期的字符串参数,返回相应日期的毫秒数;如果传入参数不能表示日期,会返回 NaN。实际上直接使用 Date 构造函数传入字符串参数,也会在后台调用 Date.parse() 方法。
  • Date.UTC():同样返回毫秒数,但传参不同(年份、011的月份、131的日子、0~23的小时、分钟、秒、毫秒),省略的参数视为0
  • ES5 增加了 Date.now() 方法

Date 类型继承的方法

  • toString():返回带有时区信息的日期时间,例如 PST,小时范围 0~23
  • toLocaleString():按照浏览器地区返回相应日期时间,没有地区信息,会包含 AM 或 PM
  • valueOf():不返回字符串,返回毫秒表示

日期格式化方法

  • toDateString()
  • toTimeString()
  • toLocaleDateString()
  • toUTCString()

日期/时间组件方法

getTime()

RegExp 类型

基本概念

var expression = / pattern / flags ;

var words = /[bc]at/gi; // 匹配所有"bat"和"cat",不区分大小写

pattern 模式

正则表达式部分,可带有一个或者多个标志

flag 标志

  • g :表示全局(global)模式
  • i :表示不区分大小写(case-insensitive)模式
  • m :表示多行(multiline)模式

元字符

( [ { \ ^ $ | ) ? * + . ] }

正则表达式中所有元字符都必须转义

创建正则表达式

字面量形式定义或 RegExp 构造函数

RegExp 构造函数接受两个参数:要匹配的正则表达式字符串、可选的标志字符串

var words = new RegExp("[bc]at", "ig");

由于参数是字符串,所有元字符需要双重转义

RegExp 实例属性

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

RegExp 实例方法

  • exec()
    var text = "mom and dad and baby";
    var pattern = /mom( and dad( and baby)?)?/gi;
    
    var matches = pattern.exec(text);
    console.log(matches.index); // 0
    console.log(matches[0]); // "mom and dad and baby"
    console.log(matches[2]); // " and baby"
    
    注意在 exec() 方法中,每次都只返回一个匹配项,如果没有应用全局标志,每次都返回第一个匹配项,如果应用了全局标志,每次返回下一个匹配项
  • test()
    var text = "000-00-0000";
    var pattern = /\d{3}-\d{2}-\d{4}/;
    
    if (pattern.test(text)) {
        alert("The pattern was matched.");
    }
    
    该方法返回的是布尔值(是否匹配)
  • toString() 与 toLocaleString() 都会返回正则表达式的字面量
  • valueOf() 返回正则表达式本身

RegExp 构造函数属性

正则表达式的属性都有一个长属性名和一个短属性名

长属性名 短属性名 说明
input $_ 最近一次要匹配的字符串
lastMatch $& 最近一次的匹配项
lastParen $+ 最近一次匹配的捕获组
leftContext $` input中lastMatch之前的文本
multiline $* 布尔值,是否使用多行模式
rightContext $' input中lastMatch之后的文本

模式的局限性

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")

    不推荐,因为导致解析了两次代码,需要解析字符串,影响性能

没有重载

函数声明与函数表达式

解析器会先读取函数声明,使其在执行任何代码前就已经可以访问,而函数表达式则需要等执行到所在代码行才会被解释执行。

alert(sum(10, 10)); // 可以正常运行
function sum(num1, num2) {
    return num1 + num2;
}

作为值的函数

ECMAScript 中的函数本身就是变量,所以也可以当作值来使用

注意:如果想要访问函数的指针但并不执行函数,需要去掉函数名后面的括号

函数内部属性

arguments

主要用途是保存函数参数

arguments.callee

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

function factorial(num) {
    if (num <= 1) {
        return 1;
    } else {
        return num * arguments.callee(num-1)
    }
}

如上面的例子,在递归调用中使用 argumnets.callee 属性,可以解除紧耦合状态,保证递归正常进行。

注意:严格模式下访问该属性会报错

this

this 引用的是函数据以执行的环境对象

函数的名字仅仅是一个包含指针的变量,即使是在不同的环境中执行,也会指向同一个函数

caller

保存着调用当前函数的函数的引用,如果在全局作用域中调用当前函数,它的值为 null。

注意:在严格模式中不能为函数的 caller 属性赋值,会报错。

函数的属性

ECMAScript 中的函数是对象,每个函数都包含两个属性:length 和 prototype

prototype

对于 ECMAScript 中的引用类型来说,prototype 是保存它们所有实例方法的真正所在。也就是说,像 toString()、valueOf() 这些方法实际上都保存在 prototype 名下,只是通过各自对象的实例进行访问而已。

在 ES5 中,prototype 属性是不可枚举的,因此无法用 for-in 实现

函数的方法

每个函数都包含两个非继承而来的方法:apply() 和 call(),作用都是设置函数体内 this 对象的值。

apply()

接受两个参数:运行函数的作用域,参数数组。其中参数数组可以是 Array 的实例,也可以是 arguments 对象。

foo.apply(this, [blue, red, green]);

call()

接受的参数:运行函数的作用域,其余参数逐个列出。

foo.call(this, blue, red, green);

实际上,apply() 与 call() 真正强大的地方在于能够扩充函数赖以运行的作用域,而且这样使用对象不需要和方法有任何的耦合关系。看以下例子:

window.color = "red";
var o = { color: "blue" };

function sayColor() {
    alert(this.color);
}

sayColor(); // red

sayColor.call(this); // red
sayColor.call(window); // red
sayColor.call(o); // blue

bind()

创建一个函数实例,this 值会被绑定到传入的参数上

基本包装类型

为了方便操作基本类型值,ECMAScript 提供了三个特殊引用类型:Boolean、Number、String

引用类型与基本包装类型的主要区别就是生存期,引用类型在离开当前作用域前都一直存在,基本包装类型只存在于代码执行的一瞬间,然后立刻被销毁。因此我们不能为基本包装类型添加属性和方法。

Object 构造函数会根据传入值的类型返回相应基本包装类型的实例。例如:

var obj = new Object("some text");
alert(obj instanceof String); // true

Boolean 类型

重写了 valueOf() 方法,返回 true 或 false;重写了 toString() 方法,返回字符串 "true" 和 "false"。

容易造成误解,建议永远不要使用。

Number 类型

重写了 valueOf() 方法,返回基本数值;重写 toString() 方法,返回字符串形式的数值。

提供了将数值格式化为字符串的方法:

  • toFixed():按照传入参数返回指定小数位数的数值的字符串表示,能够自动舍入
  • toExponential():返回以指数表示法(e表示法)表示的数值的字符串形式,传入的参数同样是用于指定小数位数
  • toPrecision():根据要处理的数值决定到底调用哪个方法

String 类型

继承的 valueOf() toString() toLocaleString() 方法都返回对象表示的字符串

字符方法

  • charAt():以字符串形式返回给定位置的字符
  • charCodeAt():以字符串形式返回给定位置的字符编码

字符串操作方法

  • concat():用于将一个或多个字符串拼接起来,返回拼接得到的新字符串,可以接受任意多个参数
  • slice():返回从开始位置到结束位置所有的项组成的新字符串。如果传入参数为负值,会将负值与字符串长度相加。
  • substring():返回从开始位置到结束位置所有的项组成的新字符串。如果传入参数为负值,会将其转换为0(注意该方法会自动将较小的值作为开始位置,较大的值作为结束位置)。
  • substr():返回从开始位置起n个项组成的新字符串。如果第一个参数为负值,会给它加上字符串长度,如果第二个参数为负值,则转换为0。

字符串位置方法

indexOf() 与 lastIndexOf() 都可以接受第二个参数,指定从哪个位置开始搜索

trim() 方法

创建一个副本,删除前置及后缀的所有空格,返回结果

字符串大小写转换方法

  • toLowerCase()
  • toLocaleLowerCase()
  • toUpperCase()
  • toLocaleUpperCase()

字符串的模式匹配方法

  • match():返回一个数组,第一项是与整个模式匹配的字符串,之后的每一项保存着捕获匹配的字符串。只接受一个参数:正则表达式 或 RegExp 对象。 本质与正则表达式的 exec() 方法相同
  • search():返回字符串中第一个匹配项的索引,如果没有找到匹配项则返回-1。接受的参数与 match() 相同。
  • replace():接受两个参数:第一个参数可以是 RegExp 对象或者字符串,第二个参数可以是字符串或者函数。 如果第一个参数是字符串,那么只会替换第一个子字符串,想要替换所有字符串需要用指定全局模式的正则表达式。
  • split():基于指定的分隔符将一个字符串分割为多个子字符串,将结果以数组形式返回。分隔符可以是字符串也可以是 RegExp 对象。可以传入第二个参数指定数组大小。

localeCompare() 方法

比较两个字符串:

  • 如果字符串在字母表中排在字符串参数前,则返回一个负数(一般是-1)
  • 如果字符串等于字符串参数,则返回0
  • 如果字符串在字母表中排在字符串参数后,则返回一个正数(一般是1)

fromCharCode() 方法

接受一个或多个字符编码,将其转换为一个字符串

单体内置对象

定义:由 ECMAScript 实现提供的、不依赖于宿主环境的对象,这些对象在 ECMAScript 程序执行前就已经存在了。例如 Object、Array、String、Global、Math

Global 对象

不属于任何其他对象的属性和方法最终都属于 Global 对象,所有在全局作用域中定义的属性和函数都是 Global 对象的属性。例如 isNaN()、parseInt()。

URI 编码方法

  • encodeURI():主要用于整个 URI,不会对本身属于 URI 的特殊字符编码(如冒号、问号、井号、正斜杠)。
  • encodeComponent():主要用于对 URI 中某一段进行编码,会对任何非标准字符进行编码。该方法使用更多。 相对应有解码用的 decodeURI() 和 decodeComponent()

eval() 方法

会将传入对象当作实际的 ECMAScript 语句来解析,然后把执行结果插入到原位置。被执行的代码具有与 eval() 执行环境相同的作用域链。

在 eval() 中创建的任何变量或函数都不会被提升,它们只在 eval() 执行的时候创建。

在严格模式下,外部访问不到 eval() 中创建的任何变量或函数,为 eval 赋值也会导致错误。

注意:使用 eval() 有代码注入的危险。

Global 对象的属性

特殊值(如 undefined、NaN、Infinity)和构造函数(如 Object、Function、RegExp、Error 等)都是 Global 对象的属性

window 对象

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

一种取得 Global 对象的方法:

var global = function() {
    return this;
} ();

Math 对象

为了保存数学公式和信息提供的公共位置,比用 JS 编写函数计算快得多

Math

属性 说明
Math.E 自然对数的底数
Math.LN10 10的自然对数
Math.LOG2E 以2为底e的对数
Math.PI Π的值
Math.SQRT1_2 1/2的平方根
Math.SQRT2 2的平方根

min() 和 max() 方法

要找到数组中的最大或最小值可以用 apply() 方法

var values = [1, 2, 3, 4, 5, 6];
var max = Math.max.apply(Math, values);

舍入方法

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

random() 方法

Math.random() 方法返回大于0小于1的一个随机数。

可以套用以下公式从某个整数范围内随机选择一个值。

值 = Math.floor(Math.random() * 可能值得总数 + 第一个可能的值)