创建对象的几种方法

时间:2022-05-30 10:48:15

工厂模式

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个步骤:

  1. 创建一个新对象
  2. 将构造函数的作用域赋给新对象(this指向新对象)
  3. 执行构造函数中的代码
  4. 返回新对象

优点:解决了对象类型识别的问题,可以规定特定的对象类型名称
缺点:每个实例上的同名函数不相等,即每个实例上的方法都是新构造出来的

原型模式

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/