注意: 本文来自阅读《JavaScript高级程序设计(第三版)》的笔记或者也可以称作是书摘吧👾
一般方式
- 构造函数
- 对象字面量
工厂模式
这种模式抽象了创建具体对象的过程。如下例子所示。
|
|
虽然解决了常见太多相似类的问题,但却没有解决对象识别的问题。
构造函数模式
像 Array
和 Object
这样的原生构造函数,在运行时会自动创建执行环境,还可以自定义对象属性和方法。如下例子所示。
|
|
与之前的工厂模式对比可以有以下发现:
- 没有显式地创建对象
- 直接将属性和方法赋给了
this
对象 - 没有
return
语句
注意: 构造函数应该以一个大写字母开头
实例化一个对象,要经过以下步骤:
- 创建一个新对象
- 将构造函数的作用域赋值给新对象(因此
this
就指向了这个新对象) - 执行构造函数中的代码(为这个类对象添加属性)
- 返回对象
person1
和 person2
分别保存着 Person
类的一个不同的实例。 这个两个对象都有一个 constructor
(构造函数)属性,该属性指向 Person
。
创建自定义的构造函数意味着将来可以将它的实例为一种特定的类型,此处正是构造函数模式胜过工厂模式的地方。
构造函数是一种特殊的函数,他可以通过 new
操作符来调用。
构造函数调用方式:
- 1.当做构造函数使用
|
|
- 2.作为普通函数使用
|
|
- 3.在对象的另一个作用域中调用
|
|
存在的问题
构造函数的方法 (即 sayName
)每次都要重新创建一遍。也就是说 person1
和 person2
的 sayName
不是同一个 Function
创建的。
可以通过
|
|
解决方法:
函数定义转移到构造函数的外部。如下例所示。
|
|
新的问题:
sayName
使得全局变量名不副实- 自定义的引用类型没有了封装性可言
原型模型
原型(
prototype
)属性:这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
prototype
就是通过构造函数而创建的那个对象实例的原型对象。
|
|
理解原型对象
当创建一个新函数的时候,就会创建一个 prototype
属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象会自动获得一个 constractor
(构造函数)属性,这个属性包含一个指向 prototype
属性所在函数的指针。如图所示,Person.prototype.constructor
指向 Person
。也就是说,可以通过这个构造函数为原型对象添加其他属性和方法。
注意: 虽然可以通过对象实例访问保存在原型中的值,却不能通过对象实例重写原型中的值。
如果在实例中添加一个属性,该属性与实例中的一个属性同名,那在实例中常见该对象,该属性会将原型中的那个属性屏蔽。
hasOwnProperty()
方法可以检测一个属性存在于实例中还是原型中。这个方法只在给定属性存在于对象实例中时,就会返回true
。
原型与 in
操作符
用法
- 单独使用。
in
操作符会在通过对象能够访问对象时返回true
,无论存在于实例还是原型中。 for-in
循环。返回的是所有能够通过对象访问的、可枚举的(enumerated)属性,既包括存在于实例中的属性和原型中的属性。不可枚举的constructor
属性,可以通过Object.keys()
和Object.getOwnPropertyName()
方法来替代for-in
循环。
更简单的原型语法
可以通过如下方式:
|
|
上面的代码将 Person.prototype
设置为等于一个以对象字面量形式创建的对象。
例外 constructor
属性不再指向 Person
。
为了解决上面的问题,可以如下
|
|
注意: 以此方式重设
constructor
属性将会导致他的[[Enumerable]]
特性被设置为true
默认情况下,constructor
属性是不可枚举的
原型的动态
注意: 实例中的指针仅指向原型,而不是指向构造函数。
原生对象的原型
可以取得默认方法的引用。例如。
12alert(typeof Array.prototype.sort); // 'function'alert(typeof String.prototype.substring); //function
还可以定义新方法
|
|
注意: 不建议在产品化的程序中修改原生对象的原型。
原型对象的问题
- 省略了为构造函数传递初始化参数这一环节,导致所有实例在默认情况下都将取得相同的属性值。
- 最大的问题在于其共享的本性导致的。原型中所有属性都是实例共享的。对于函数适合。但是对于类型值的属性来说,问题就突出了。
组合使用构造函数和原型模式
创建自定义类型的最常见方式。
特点
构造函数模式用于定义实例属性;原型模式用于定义方法和共享的属性。
好处
- 每个实例都会有自己的一份实例属性的副本
- 但同时又共享着对方法的引用
- 最大限度的节省内存。
- 还支持向构造函数传递参数
例子
|
|
此种方式是目前 ECMAScript
中使用最广泛、认同度最高的一种创建自定义类型的方法。 换句话说,这是用来定义引用类型的一种默认模式。
动态原型模式
动态原型模式将所有信息封装在构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同事使用构造函数和原型的优点。如例子所示。
|
|
寄生构造函数模式
主要思想: 创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后返回新的对象。下面是例子。
|
|
补充说明:
- 返回的对象与构造函数或者与构造函数的原型属性之间没有关系,也就是说构造函数返回的对象与在构造函数外创建的对象没有什么不同。
- 不能依赖
instanceof
操作符来确定对象类型。 - 在能使用别的模式的情况下,不要使用该模式。
稳妥构造函数模式
是什么?
没有公共属性 | 其方法也不引用 this
的对象
代码示例
|
|