JS 创建对象的7种方法(二)

3.原型模式(Prototype)

我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象。使用原型对象的好处是让所有实例共享它所包含的属性和方法。

function Person(){

}
Person.prototype.name = "Bob";
Person.prototype.age = 18;
Person.prototype.job = "Developer";
Person.prototype.sayName = function(){
    alert(this.name);
}

var person1 = new Person();
var person2 = new Person();

3.1 理解原型对象

只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会获得一个constructor属性,这个属性指向prototype属性所在的函数。

当调用构造函数创建一个新实例后,该实例的内部包含一个指针(内部属性--[[Prototype]]),指向构造函数的原型对象。 虽然我们无法访问到[[Prototype]],但可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系。如果[[Prototype]]指向调用isPrototypeOf()方法的对象,那么这个方法就返回true。

alert(Person.prototype.isPrototypeOf(person1));    //true
alert(Person.prototype.isPrototypeOf(person2));    //true

Object.getPrototypeOf()方法返回[[Prototype]]的值:

alert(Object.getPrototypeOf(person1) == Person.prototype);   //true
alert(Object.getPrototypeOf(person1).name);    //Bob

每当代码读取某个对象的属性时,都会执行一次搜索。搜索首先从对象实例本身开始,如果在实例中找到了,则返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象。

我们可以通过对象实例访问保存在原型中的值,但不能通过对象实例改变原型中的值:

person1.name = "Peter";
person1.sayName();    //"Peter" 来自实例
person2.sayName();    //"Bob"   来自原型

使用hasOwnProperty()方法可以检测一个属性是存在于实例中,还是存在于原型中。接上面的例子:

alert(person1.hasOwnProperty("name"));    //true  
alert(person2.hasOwnProperty("name"));    //false
alert(person1.hasOwnProperty("age"));       //false
    

3.2 原型与in操作符

 in操作符会在 通过对象能访问属性时返回true, 无论该属性存在于实例中还是原型中。

alert("name" in person1);    //true 来自实例
alert("name" in person2);    //true 来自原型

同时使用hasOwnProperty()方法与in操作符,就可以确定该属性的位置。

function hasPrototypeProperty(object, name){
    return !object.hasOwnProperty(name) && (name in object);        
}
alert(hasPrototypePropoty(person1, "name"));  //false
alert(hasPrototypePropoty(person2, "name")); //true

使用Object.keys()方法可以取得对象上所有可枚举的实例属性:

var keys = Object.keys(Person.prototype);
alert(keys);     //name, age, title, sayName
var keys1 = Object.keys(person1);
alert(keys1);  //name

Object.getOwnPropertyNames() 可以或得所有实例属性(包括不可枚举的)

alert(Object.getOwnPropertyNames(Person.prototype));    //constructor,name,age,title,sayName

3.3 更简单的原型方法

function Person(){
}

Person.prototype = {
    name: "Bob",
    age: 29,
    title: "Developer",
    sayName: function(){
        alert(this.name);
    }
};

 在上面的例子中,我们将Person.prototype设置为等于一个以对象字面量形式创建的新对象。最终结果相同,但constructor属性不再指向Person。上面的例子本质上重写了默认的prototype对象,因此constructor属性也就变成了新对象的constructor属性(指向Object构造函数)。

3.4原型对象的问题

  1. 原型模式省略了为构造函数传递参数,所以所有实例在默认情况下都取得相同的属性值。

  2. 对于引用类型值:

function Person(){
}

Person.prototype = {
    name: "Bob",
    age: 29,
    title: "Developer",
    friends:["Court", "Ann"],
    sayName: function(){
        alert(this.name);
    }
}; 

var person1 = new Person();
var person2 = new Person();

person1.friends.push("Alice");

alert(person1.friends);    // Court, Ann, Alice
alert(person2.friends);    // Court, Ann, Alice
原文地址:https://www.cnblogs.com/PrajnaParamita/p/5750507.html