js中的原型对象

我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。

所以说,无论我们什么时候创建了一个新函数,就会一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,如下所示:

function Person() {
}

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

这里的Person.prototype.constructor默认指向Person

js中提供一种方法,可以通过isPrototypeOf()这个方法来确定对象是否有的相同的原型属性。

var person = new Person();
Person.prototype.isPrototypeOf(person); //true

虽然可以通过对象实例访问保存在原型中的值,但是却不能通过该对象实例重写原型中的值。

var person1 = new Person();
var person2 = new Person();
person1.name = 'Lisi';
console.log(person1.name);  //Lisi
console.log(person2.name);  //Zhangsan

虽然person1输出的是Lisi,但其实修改的是其对象实例中的属性,即为其实例上添加了一个属性,然后就屏蔽了原型对象中保存的属性,所以这里person1输出为Lisi,同时person2实例输出为Zhangsan。当然,可以使用delete删除实例上的属性,之后就可以访问其原型上的属性了。

delete person1.name

当使用字面量的方式来书写原型对象时,会导致其constructor属性不在指向原函数,但是可以手动指明的方式来声明。

function Person() {
}

Person.prototype = {
    constructor: Person,
    name: 'Zhangsan',
    sayName: function () {
        console.log(this.name)
    }
}

var person1 = new Person();
console.log(person1.sayName())

但是,原生的constructor是不可枚举的(什么是可枚举?就是说可以通过for-in循环或者Object.keys()中拿到对象的属性),那么可以使用Object.defineProperty()来声明属性。

Object.defineProperty(Person.prototype, 'constructor', {
    enumerable: false,
    value: Person
})

这样就没什么问题了。

还有一点需要注意,新建实例后,再重写原型,将会切断现有实例与原型之间的联系,故新实例无法调用原型上的方法,如下的实例将会出现错误。

function Person() {
}

var person = new Person();

Person.prototype = {
    name: 'Zhangsan',
    sayName: function () {
        console.log(this.name)
    }
}

Object.defineProperty(Person.prototype, 'constructor', {
    enumerable: false,
    value: Person
})

console.log(person.sayName())   //error
如果您觉得本文对您有用,欢迎捐赠或留言~
微信支付
支付宝

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注