# prototypeDesign **Repository Path**: lvxiaowu/prototypePattern ## Basic Information - **Project Name**: prototypeDesign - **Description**: 设计模式之原型模式 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-11-06 - **Last Updated**: 2020-12-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 原型模式 ## 概念/特点 - 概念:就是创建一个共享的原型,通过拷贝这个原型来创建新的类,用于创建更多同类型的对象。 - 特点:不需要知道对象构建的细节,直接从对象上克隆出来。 ## 实现 1. 使用 typescript ```typescript interface Clonable { clone(): T; } class Person implements Clonable { name: string | undefined; age: number | undefined; getName(): string { return '你的名字:' + this.name; } clone(): Person { let target = new Person(); target.name = this.name; target.age = this.age; target.getName = this.getName; return target; } } let p = new Person(); p.name = '小丽'; p.age = 18; let cloneObj = p.clone(); let cloneObj1 = p.clone(); ``` 2. 使用 prototype ```javascript let personPrototype = { init: function(name) { this.name = name; }, getName: function() { console.log('你的名字:' + this.name); } }; function clone(name) { function F() {} F.prototype = personPrototype; let f = new F(); f.init(name); return f; } let p = clone('小明'); p.getName(); ``` 3. 使用 [Object.create(prototype, optionalDescriptorObjects)](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create 'Object.create') ```javascript let personPrototype = { name: '小丽', cars: ['兰博基尼', '凯迪拉克'], getName: function() { console.log('你的名字:' + this.name); } }; let p = Object.create(personPrototype, { name: { value: '小明' } }); p.getName(); ``` ## 适应场景 1. 当对象的构建比较复杂时或者想得到目标对象相同内容的对象时可以考虑原型模式。 ## 优/缺点 - 优点:隐藏了创建新实例的复杂性,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。 - 缺点:对于包含引用类型值的属性来说,所有实例在默认的情况下都会取得相同的属性值。 # JS 中的原型和原型链 ## 讲原型的时候,我们应该先要记住以下几个要点,这几个要点是理解原型的关键: 1. 所有的引用类型(数组、函数、对象)可以自由扩展属性(除 null 以外) 2. 所有的引用类型都有一个’\_ _proto_ \_ ’属性(也叫隐式原型,它是一个普通的对象) 3. 所有的函数都有一个’prototype’属性(这也叫显式原型,它也是一个普通的对象) 4. 所有引用类型,它的'\_ _proto_ \_ '属性指向它的构造函数的’prototype’属性 5. 当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的'\_ _proto_ \_ '属性(也就是它的构造函数的’prototype’属性)中去寻找 ## 原型图 ![原型图](./src/static/prototype.png) - 首先,fn 的构造函数是 Foo()。所以: ```javascript fn.__proto__ === Foo.prototype; ``` 又因为 Foo.prototype 是一个普通的对象,它的构造函数是 Object,所以 ```javascript Foo.prototype.__proto__ === Object.prototype; ``` 通过上面的代码,我们知道这个 toString()方法是在 Object.prototype 里面的,当调用这个对象的本身并不存在的方法时,它会一层一层地往上去找,一直到 null 为止。 ## 原型链 - 当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的’prototype’属性中去寻找。形成的‘查找链’称为原型链(基于‘\_ _ proto _ \_ ’向上查找的机制) ## new 的作用 ```javascript let Foo = function() {}; let fn = new Foo(); ``` 1. 创建了一个空对象 ```javascript let obj = {}; ``` 2. 设置原型链 ```javascript obj.__proto__ = Foo.prototype; ``` 3. 让 Foo 中的 this 指向 obj,并执行 Foo 的函数体。 ```javascript let result = Foo.call(obj); ``` 4、判断 Foo 的返回值类型 - 如果函数没有返回其他对象,那么 new 表达式中的函数调用会 自动返回 这个新对象。 ```javascript if (typeof result == 'object') { fn = result; } else { fn = obj; } ```