原型模式

每一个函数都有一个prototype(原型)属性

prototype就是通过调用构造函数而创建的那个对象实例的原型对象。

可以让所有对象实例共享它所包含的属性和方法。不方便的是很容易造成属性和方法的覆盖。所以会有一些解决方法。


function Lin(){}

Lin.prototype.name="linshui";

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

var test1 = new Lin();
test1.sayName(); //linshui

var test2 = new Lin();
test2.sayName();//linshui

理解原型对象

只要创建一个新函数,就会为这个函数创建一个prototype,这个属性指向函数的原型对象。

默认情况下,原型对象会获得constructor(构造函数)属性。这个函数包含一个指向prototype属性所在函数的指针。

比如

console.log(Lin.prototype.constructor) //指向Lin

因此Lin.prototype指向原型对象,Lin.prototype.constructor又指回了Lin.

可以用isPrototypeof()来确定是否属于对象原型.

console.log(Lin.prototype.isPrototypeOf(test2)) //true

或者用getPrototypeOf()

console.log(Object.getPrototypeOf(test2) === Lin.prototype)//true

hasOwnProperty()检测一个属性是否存在于一个实例中。

function Lin(){}

Lin.prototype.name="linshui";

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

var test1 = new Lin();
var test2 = new Lin();

console.log(test2.hasOwnProperty("name"))//false 因为来自于原型而不是实例

test2.test = "2333";

console.log(test2.hasOwnProperty("test"))//true 因为来自实例。

test2.name="test2";

console.log(test2.hasOwnProperty("name"))//true
因为实例重写属性使其属于实例

in操作符会在通过对象能够访问给定属性时返回true。

比如:

function Lin(){}

Lin.prototype.name="linshui";

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

var test1 = new Lin();
var test2 = new Lin();
test2.test = "233";
console.log("name" in test2)//true 从原型中找到

console.log("test" in test2)//true 从实例中找到

所以,只要In操作符返回true而hasOwnProperty()返回false,就可以确定属性是原型中的属性。

原型语法

用一个包含所有属性和方法的对象字面量重写整个原型对象。

function Lin(){}

Lin.prototype = {
    name : "Zhaoying",
    sayName : function(){
        console.log(this.name)
    }
};

var test = new Lin();
console.log(test.constructor == Lin); //false
console.log(test.constructor == Object); //true

本质上是重写了默认的prototype对象,而且constructor属性变成了新对象的constructor(指向Object构造函数)。无法通过constructor确定对象类型.

可以手工写回指向。

function Lin(){}

Lin.prototype = {
    constructor : Lin,
    name : "Zhaoying",
    sayName : function(){
        console.log(this.name)
    }
};

在实例中添加的函数在任何以原型为基础的实例都能访问,这是因为实例与原型之间的连接不过是一个指针,而不是副本。

然而如果重写整个原型对象,调用构造函数会为实例添加一个指向最迟原型的指针,把原型修改成另一个对象意味着切断了构造函数与最初原型之间联系。实例中指针仅指向原型,而不是指向构造函数。

function Lin(){}

var test = new Lin();

Lin.prototype = { //重新原型,切断原有原型与任何之前已经存在的对象实例之间的联系。
    constructor : Lin,
    name : "Zhaoying",
    sayName : function(){
        console.log(this.name)
    }
};


console.log(test.sayName); //undefined

组合使用构造函数模式,原型模式

构造函数模式用于定义实例函数,原型模式用于定义方法和共享的属性

function test(name,age){
    this.name = name;
    this.age = age;
}

Lin.prototype = {
    constructor : Lin,
    name : "Zhaoying",
    sayName : function(){
        console.log(this.name)
    }
};