原型模式(prototype): 是指用原型实例指向创建对象的种类, 并且通过拷贝这些原型创建新的对象.
真正的原型继承是作为最新版的 ECMAScript5 标准提出的, 使用 Object.create 方法来创建这样的对象, 该方法创建指定的对象, 其对象的 prototype 有指定的对象(也就是该方法传进的第一个参数对象), 也可以包含其他可选的指定属性. 例如 Object.create(proto, [propertiesObject])
过程
Prototype => new ProtoExam => clone to new Object;
创建一个原型 =>new 一个原型实例 =>拷贝原型实例到新的对象
- // 创建一个原型并且添加一些属性 this.XXX 添加
- function Person () {
- this.name = 'Uzi'
- this.sex = '21'
- this.age = '男'
- this.getName=function () {
return ` 姓名:${this.name}`
- }
- }
- // 通过 .prototype.XXX 方式 添加也可
- Person.prototype.getMsg = function () {
return ` 姓名: ${this.name}, 年龄: ${this.age}, 性别:${this.sex}`
- }
- // new 一个原型实例
- const proto = new Person();
- // 通过 Object.create 拷贝原型实例
- const person1 = Object.create(proto);
- const person2 = Object.create(proto);
- person2.name = 'Ming'
- person2.sex = '20'
- person2.age = '男'
- console.log(person1.getName()) // 姓名: Uzi
- console.log(person2.getName()) // 姓名: Ming
- console.log(person1.getMsg()) // 姓名: Uzi, 年龄: 男, 性别: 21
- console.log(person2.getMsg()) // 姓名: Ming, 年龄: 男, 性别: 20
复制代码
此段代码也证明了: 原型挂在实例的原型链上, 修改实例不影响原型, 即为深拷贝
原型模式, 一般用于抽象结构复杂, 但内容组成差不多, 抽象内容可定制, 新创建只需在原创建对象上稍微修改即可达到需求的情况.
优点
方法不会重新创建(只要 new 一个原型实例)
缺点:
所有的属性和方法都共享
不能初始化参数
Object.create
定义
创建一个具有指定原型且可选择性地包含指定属性的对象
Object.create(proto, [propertiesObject])
proto : 新创建对象的原型对象
propertiesObject : 可选. 如果没有指定为 undefined, 则是要添加到新创建对象的可枚举属性 (即其自身定义的属性, 而不是其原型链上的枚举属性) 对象的属性描述符以及相应的属性名称. 这些属性对应 Object.defineProperties() https://developer.mozilla.org/zh-CN/docs/web/JavaScript/Reference/Global_Objects/Object/defineProperties 的第二个参数.
使用
1. 定义原型对象
- // 添加属性方法 this.XXX 方式
- function Person () {
- this.name = 'Uzi'
- this.sex = '21'
- this.age = '男'
- this.getName=function () {
return ` 姓名:${this.name}`
- }
- }
- // 添加属性方法 .prototype.XXX 方式
- Person.prototype.getMsg = function () {
return ` 姓名: ${this.name}, 年龄: ${this.age}, 性别:${this.sex}`
}
复制代码
2. 使用 Object.create 拷贝 原型
1. 以 Person.prototype 创建对象
- const person1 = Object.create(Person.prototype, {
- position:{value: 'ADC', writable: true}
- })
- console.log(person1.position) // ADC
- console.log(person1.getMsg()) // 姓名: undefined, 年龄: undefined, 性别: undefined
- console.log(person1.getName()) // Uncaught TypeError: person1.getName is not a function
复制代码
这说明 person1 就具有 Person 原型方法 getMsg 的方法, 但是不具有 Person 下成员属性
name,sex,age,getName
2. 以实例化的 Person 做原型
- const proto = new Person(); // 实例化的 Person
- const person2 = Object.create(proto, {
- position: { value: 'SUP', writable: true }
- });
- person2.name = 'Ming'
- person2.sex = '20'
- person2.age = '男'
- console.log(person2.position) // SUP
- console.log(person2.getMsg()) // 姓名: Ming, 年龄: 男, 性别: 20
- console.log(person2.getName()) // 姓名: Ming
复制代码
这说明, 这样创建的 person2 就具有 Person 的所有的成员属性
name,sex,age,getName
以及 getMsg 原型方法; 并添加了一个 position 只读 数据属性;
使用 Object.create 实现子类继承
1. 以 Person.prototype 对象, 做为 Son 的原型
- function Son () {
- Person.call(this); // 不然无法 Person 成员属性
- }
- Son.prototype = Object.create(Person.prototype, {
- position: { value: '儿子' }
- });
- Son.prototype.sonMethod = function() {
- return this.name || this.position;
- }
- const son1= new Son()
- console.log(son1.position) // 儿子
- console.log(son1.getMsg()) // 姓名: Uzi, 年龄: 男, 性别: 21
- console.log(son1.sonMethod()) // Uzi
- console.log(son1.getName()) // 姓名: Uzi
复制代码
2. 以实例化的 Person 对象, 做为 Son 的原型
- const proto = new Person();
- function Son () {
- }
- Son.prototype = Object.create(proto, {
- position: { value: '儿子' }
- });
- const son1= new Son()
- console.log(son1.position) // 儿子
- console.log(son1.getMsg()) // 姓名: Uzi, 年龄: 男, 性别: 21
- console.log(son1.getName()) // 姓名: Uzi
复制代码
这样 Son 实例化后, 就可以获取到 Person 所有的属性及原型方法, 以及创建一个只读数据属性 position;
Object.create 的实现
- Object.prototype.create = function (obj) {
- if (Object.prototype.create) {
- return Object.prototype.create
- } else {
- function F () {
- F.prototype = obj; // 以传入参数为原型构造对象
- return new F();
- }
- }
- }
复制代码
由此也能看出返回了一个新对象, 深拷贝
Object.create,{},new Object() 对比
Object.create 指定了拷贝的原型对象, Object.create(null)的时候对象不具备任何原型属性,{},new Object(), 具备对象的原型属性
来源: https://juejin.im/post/5b728d61518825613f7f3992