JS原型创建对象

  • 原型出现的原因
    创建对象时,用Object构造函数或对象字面量创建多个对象时,产生大量重复代码。于是出现了工厂模式。

    工厂模式,软件工程中流行的设计模式,抽象了创建具体对象的过程,以函数封装特定接口创建对象的细节

    function createPerson(name, age) {
    	 var o = new Object();
    	o.name = name;
    	o.age = age;
    	o.sayName = function() {
    		console.log(this.name);
    	}
    
    	return o;
    }
    
    var person1 = createPerson();
    

    工厂模式解决了创建多个相似对象的问题,却不能识别创建的对象的类型,所以出现了构造函数模式。

    构造函数模式,构造函数包括原生的构造函数如Object, Array等,也可以自定义构造函数。

    // 构造函数应始终以大写字母开头,并且与其他函数不同的地方在于始终以new操作符调用
    function Person(name, age) {
      this.name = name;
      this.age = age;
      this.sayName = function() {
        console.log(this.name);
      }
    }
    
    var person1 = new Person('yang', 18);
    

    但是构造函数的问题在于,每个方法都要在每个实例上重新创建一遍。因为函数也是对象,上面例子中的sayName方法可以认为是this.sayName = new Function('console.log(this.name)')。因此这样没有必要,可以把完成相同功能的函数定义移到构造函数外面,但是这就变成了全局函数不太合理,并且如果对象方法很多就会定义大量的全局函数。于是出现了原型模式创建对象。

  • 原型

    我们创建的每个函数都有一个prototype属性(指针),指向一个原型对象,该对象包含所有实例共享的属性和方法。

    // 最好不要直接重写原型对象,会切断现有原型与之前任何已经存在的对象实例之间的联系(红宝书p157)
    function Person() {}
    Person.prototype.name = 'yang';
    Person.prorotype.age = 18;
    Person.prototype.sayName = function() {}
    
    var person1 = new Person();
    person1.sayName();
    

    无论何时,只要创建了一个新函数,就会为该函数创建一个prototype属性,该属性指向函数原型对象。默认情况下,所有原型对象都有一个constructor属性,该属性包含一个指向包含prototype属性所在函数的指针
    创建自定义构造函数,原型对象默认只会取得constructor属性,其他方法都是从Object继承的。

    调用构造函数创建实例,该实例包含一个内部指针[[prototype]],指向构造函数的原型。(脚本中没有标准方式访问该指针,但是有些浏览器支持__proto__),该属性是实例指向原型对象。 如下图。代码读取对象属性时,先从对象实例寻找,没有的话,会继续查找其原型对象是否有该属性。
    在这里插入图片描述

几个方法:

  • isPrototypeOf()判断是否是原型对象,例如:Person.prototype.isPrototypeOf(person1)
  • Object.getPrototypeOf()获取对象原型
  • hasOwnPrototy判断属性是否在实例中,结合in操作符,可判断对象在实例还是原型中。!object.hasOwnProperty(xxx) && (xxx in object)
  • for...in返回所有能访问并可枚举的属性,包括实例和原型中的属性。
  • Object.keys(),获取所有可枚举的实例属性
  • Object.getOwnPropertyNames()获取所有实例属性,包括不可枚举类型

原型模式创建对象最大的问题是共享导致,对于包含引用类型值的属性而言,例如当原型中某个属性是数组,当创建实例并改变该属性时,也会影响其他的以该原型对象为原型的实例。所以创建自定义类型的最常见方式,是组合使用构造函数与原型模式

组合构造函数与原型模式,构造函数定义实例属性,原型模式定义方法和共享的属性,使每个实例有一份自己的实例属性副本,但是同时共享着对方法的使用。最大限度的节省内存,并且支持向构造函数传参。
这种模式是ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法。

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.friends = ['A', 'B'];
}

Person.prototype.sayName = function() {
  console.log(this.name);
}

var person1 = new Person('yang', 18);
var person2 = new Person('yue', 15);

person1.friends.push('C');
person2.friends.push('MM');

console.log(person1.friends); //  ["A", "B", "C"]
console.log(person2.friends); //  ["A", "B", "MM"]

还存在动态原型模式,寄生构造函数模式以及稳妥构造函数模式(红宝书p159-p162),了解下就好,有时间再加。

猜你喜欢

转载自blog.csdn.net/u011141492/article/details/88926048