引用类型

引用类型的值(对象)是引用类型的一个实例。在 ECMAScript 中,引用类型是一种数据结构,用于将数据和功能组织在一起。它也常被称为,但这种称呼并不妥当。尽管ECMAScript从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基本结构。引用类型有时候也被称为对象定义,因为它们描述的是一类对象所具有的属性和方法。

Object

到目前为止,我们看到的大多数引用类型值都是 Object 类型的实例;而且, Object 也是
ECMAScript 中使用最多的一个类型。

创建对象:

1
2
3
4
5
// new 操作符调用构造函数
let a = new A();
// 对象字面量
// 在通过对象字面量定义对象时,实际上不会调用 Object 构造函数。
let b = {};

访问属性:

1
2
a.b
a['b'] // 用方括号的优点是可以通过变量来访问属性或者属性名可能导致错误时会避免报错

Array

创建数组:

1
2
3
4
let a = [];
let b = new Array(1,2,3); // [1,2,3]
let c = new Array(3); //[ , , ] 三个为空元素的数组
let d = new Array('3'); // ['3']

数组索引:

1
2
3
4
5
6
let a = [];
a[2] = 1;
a // [empty,empty,1] // 可以通过索引来控制数字长度
let b = [];
b.length = 3;
b // [empty,empty,empty] // 可以通过设置length来改变数组

常规方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 栈方法
let a = [];
a.push(1,2) // [1,2]
a.pop(); // 2 删除最后一项并返回
a // [1]
// 队列方法
let b = [1,2,3];
b.shift(); // 1 删除第一项并返回
b // [2,3]
b.unshift(1,2)
b // [1,2,2,3] 从前面推入两项
// 排序方法
let c = [1,2,3];
c.reverse()
c // [3,2,1] 将数组的顺序反转
let d = [1,5,15]
d.sort()
d // 1,15,5 sort方法调用每个元素的toString方法,字符串比较是比较首字母
d.sort((a,b)=>{
return a-b;
})
d // [1,5,15] sort接收一个函数,如果返回负数那么前一个元素就排在后一个元素前面。
// 操作方法
let e = [1,2,3];
e = e.concat(3,4,[5,6])
e // [1,2,3,4,5,6] 合并数组
e = e.slice(1,4)
e // [2,3,4] 包括前面不包括后面[1,4) 需要注意的是concat和slice都不会改变原数组
e.splice(0,1,'replace')
e // ['replace', 3, 4] 接收3个参数,起始位置,删除数量,添加元素 可以用于删除,插入,替换
// 位置方法
let f = [1,2,3,1]
e.indexOf(1) // 0
e.lastIndexOf(1) // 3
// 迭代方法
every() :对数组中的每一项运行给定函数,如果该函数对每一项都返回 true ,则返回 true
filter() :对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。
forEach() :对数组中的每一项运行给定函数。这个方法没有返回值。
map() :对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
some() :对数组中的每一项运行给定函数,如果该函数对任一项返回 true ,则返回 true
以上方法都不会修改数组中的包含的值。
// 归并方法
let g = [1,2,3];
g.reduce((prev, cur, index, array)=>{
return prev + cur;
})
// 接收4个参数,prev 上一个元素的结果(最开始就是第一个元素), cur 当前元素, index 当前元素的编号, array 执行reduce的数组。
// 还有一个reduceRight,从数组的最后一个元素开始迭代。

Function

每个函数都是 Function 类型的实例,而且都与其他引用类型一样具有属性和方法。由于函
数是对象,因此函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定。

定义函数:

1
2
3
4
5
6
// 函数声明语法定义
function foo() {}
// 函数表达式
var foo = function(){}
// 构造函数(不推荐)
var foo = new Function('arg1','arg2','return arg1 + arg2');

实际上,解析器在向执行环境中加载数据时,对函数声明和函数表达式并非一视同仁。解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行。

函数可以作为参数或者是返回值参与到代码中,这统称为高阶函数

函数内部属性
  • arguments:

用于保存传入函数的所有参数,是一个类数组的对象。还有一个名叫callee的属性,指向拥argument的函数。

1
2
  • this:

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

函数的名字仅仅是一个包含指针的变量而已。因此,即使是在不同的环境中执行,全局的 sayColor() 函数与 o.sayColor() 指向的仍然是同一个函数。改变的只是他们的执行环境,即函数内的this。

  • caller:

这个属性中保存着调用当前函数的函数的引用(注意只是函数,而不是对象),如果是在全局作用域中调用当前函数,它的值为 null 。

1
2
3
4
5
6
7
8
9
10
11
12
13
function outer() {
console.log(outer.caller);
inner();
}
function inner() {
console.log(inner.caller);
console.log(arguments.callee.caller) //当函数在严格模式下运行时,访问 arguments.callee 会导致错误。ECMAScript 5 还定义了arguments.caller 属性,但在严格模式下访问它也会导致错误,而在非严格模式下这个属性始终是undefined 。定义这个属性是为了分清 arguments.caller 和函数的 caller 属性。
}
let a = {outer:outer};
a.outer();
// null
// Function outer
函数本身的属性和方法
  • length

跟普通意义上的length不同,函数的length表示的是可以接收参数的数量

  • call,apply,bind

三个方法都是改变函数的执行环境,前两者的区别是call传参数是按单个传递,apply是数组;bind是返回绑定好的方法,不立即执行。

1
2
3
4
5
6
7
let a = {foo:function(){
console.log(this.name)
},name:'1'};
let b = {name:'2'};
a.foo.call(b); // 2
let foo1 = a.foo.bind(b);
foo1(); //2

基本包装类型

我们知道,基本类型值不是对象,因而从逻辑上讲它们不应该有方法(尽管如我们所愿,它们确实有方法,比如string.substring())。其实,为了让我们实现这种直观的操作,后台已经自动完成了一系列的处理。

  • 创建 String 类型的一个实例;

  • 在实例上调用指定的方法;

  • 销毁这个实例。

    可以将以上三个步骤想象成是执行了下列 ECMAScript 代码。

    1
    2
    3
    var s1 = new String("some text");
    var s2 = s1.substring(2);
    s1 = null;

自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。这意味着我们不能在运行时为基本类型值添加属性和方法

Boolean
1
2
3
4
5
6
var falseObject = new Boolean(false);
var result = falseObject && true;
console.log(result); // false
typeof falseObject // Object
typeof false // Boolean
false instanceof Boolean // false

Boolean 类型的实例重写了 valueOf() 方法,返回基本类型值 true 或 false ;重写了 toString()方法,返回字符串 “true” 和 “false” 。

小结:

对象在 JavaScript 中被称为引用类型的值,而且有一些内置的引用类型可以用来创建特定的对象,现简要总结如下:

  • 引用类型与传统面向对象程序设计中的类相似,但实现不同;
  • Object 是一个基础类型,其他所有类型都从 Object 继承了基本的行为;
  • Array 类型是一组值的有序列表,同时还提供了操作和转换这些值的功能;
  • Date 类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;
  • RegExp 类型是 ECMAScript 支持正则表达式的一个接口,提供了最基本的和一些高级的正则表达式功能。
  • 函数实际上是 Function 类型的实例,因此函数也是对象;而这一点正是 JavaScript 最有特色的地方。由于函数是对象,所以函数也拥有方法,可以用来增强其行为。因为有了基本包装类型,所以 JavaScript 中的基本类型值可以被当作对象来访问。

三种基本包装类型分别是: Boolean 、 Number 和 String 。以下是它们共同的特征:

  • 每个包装类型都映射到同名的基本类型;
  • 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据操作;
  • 操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象。

在所有代码执行之前,作用域中就已经存在两个内置对象: Global 和 Math 。在大多数 ECMAScript实现中都不能直接访问 Global 对象;不过,Web 浏览器实现了承担该角色的 window 对象。全局变量和函数都是 Global 对象的属性。 Math 对象提供了很多属性和方法,用于辅助完成复杂的数学计算任务。