工厂模式
12345678910111213141516 |
function createPersion(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function() { console.log(this.name); }; return o;}var person1 = createPersion('a', 29, 'jobA');var person2 = createPersion('b', 30, 'jobB');console.log(person1 instanceof createPersion) // falseconsole.log(person1 instanceof Object) // true |
优点:创建多个相似对象
缺点:无法知道对象的类型
构造函数模式
123456789101112131415 |
function Person (name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function() { console.log(this.name); } //等价于 new Function(...)}var person1 = new Person('a', 29, 'jobA');var person2 = new Person('b', 30, 'jobB');console.log(person1 instanceof Person) // trueconsole.log(person1 instanceof Object) // false |
构造函数以大写字母开头
用new
的方式调用构造函数,会经历以下4个步骤:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(
this
指向新对象) - 执行构造函数中的代码
- 返回新对象
优点:解决了对象类型识别的问题,可以规定特定的对象类型名称
缺点:每个实例上的同名函数不相等,即每个实例上的方法都是新构造出来的
原型模式
12345678910111213141516 |
function Person() {}Person.prototype.name = 'a';Person.prototype.age = 29;Person.prototype.job = 'jobA';Person.prototype.sayName = function() { console.log(this.name);}var person1 = new Person();person1.sayName(); // avar person2 = new Person();person2.sayName(); // aconsole.log(person1.sayName === person2.sayName) // true |
优点:共享了属性
缺点:共享的引用类型的数据(如:Array),也被所有实例共享了
理解原型对象
[[Prototype]]的链接存在于实例与构造函数的原型之间,不是存在于实例与构造函数之间
1234567891011 |
// isPrototypeOfconsole.log(Person.prototype.isPrototypeOf(person1)) // true// getPrototypeOfconsole.log(Object.getPrototypeOf(person1) == Person.prototype); // true// hasOwnPropertyconsole.log(person1.hasOwnProperty('name')); // false// in console.log('name' in person1) // true |
在读取对象中的属性时,先搜索实例,后搜索原型。
取得对象上所有可枚举的实例属性
Object.keys()
包括原型中与实例中的属性
更简单的原型语法
1234567891011121314151617 |
function Person() {}// 相当于重写了原型Person.prototype = { name: 'a', age: 29, job: 'jobA', sayName: function() { console.log(this.name); }}// 将原型对象的'constructor'属性指向Person构造函数Object.defineProperty(Person.prototype, 'constructor', { enumberable: false, value: Person,}); |
组合使用构造函数模式和原型模式
123456789101112131415161718192021222324 |
// 不应该共享的属性,用构造函数模式function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.friends = ['A', 'B'];}// 需要共享的属性,用原型模式共享Person.prototype = { constructor: Person, sayName: function() { console.log(this.name); }}var person1 = new Person('a', 29, 'jobA');var person2 = new Person('b', 30, 'jobB');person1.friends.push('C');console.log(person1.friends); // 'A', 'B', 'C'console.log(person2.friends); // 'A', 'B'console.log(person1.friends === person2.friends); // falseconsole.log(person1.sayName === person2.sayName); // true |
集合了构造函数模式和原型模式的优点
动态原型模式
1234567891011121314 |
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; if(typeof this.sayName !== 'function') { // 同样不能用对象字面量重写原型 Person.prototype.sayName = function() { console.log(this.name); }; }}var friend = new Person('a', 39, 'jobA');friend.sayName(); |
寄生构造函数模式
12345678910111213 |
function Person(name, age, job) { var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function() { console.log(this.name); } return o;}var friend = new Person('a', 29, 'jobA');friend.sayName(); // 'a' |
Person构造函数在原有Object的基础上添加了额外的属性和方法,而没有改变Object本身
优点:可以在不改变原有构造函数的前提下,为新构造函数添加方法
缺点:无法使用instanceof确定对象类型
稳妥构造函数模式
要求:
- 新创建对象的实例方法不引用this
- 不使用new操作符调用构造函数
123456789101112131415 |
function Person(name, age, job) { var o = new Object(); // 定义私有变量和函数 var name = name; o.sayName = function() { console.log(name); } return o;}var friend = Person('a', 29, 'jobA');friend.sayName(); // 'a' |
优点:除了sayName方法,没有其他方法可以访问传入构造函数中的原始数据
缺点:不能用过instanceof方法确定对象类型
转载:http://cthblog.cn/2017/02/28/%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E6%B3%95/