浅谈JavaScript 覆盖原型以及更改原型
什么是原型
JavaScript 中,每一个对象都有一个原型对象,原型对象中存储了这个对象的方法和属性。如果对象中没有此属性或方法,则会去原型对象中查找,如果原型对象中仍然找不到,再去原型的原型中查找,形成原型链。最终,如果在原型链中还是找不到,则返回 undefined。
下面是一个示例:
function Person() {}
Person.prototype.name = '张三';
Person.prototype.age = 20;
Person.prototype.sayName = function() { console.log(this.name); };
var person1 = new Person();
person1.sayName(); // 输出 "张三"
在这个示例中,定义了一个构造函数 Person,将其原型中的 name、age 和 sayName 方法分别设置为 '张三'、20 和打印 name 的方法。之后通过 Person 构造函数创建了一个实例 person1,最终输出 person1 的 name 属性,因为 name 属性在原型链中被找到了。
覆盖原型
在上面的示例中,我们可以修改 Person 的原型属性,来改变所有实例的属性。
Person.prototype.name = '李四';
person1.sayName(); // 输出 "李四"
在这里,我们将 Person 的原型属性 name 的值修改为 '李四',再次通过 person1.sayName() 输出,结果变为了 '李四'。
在这里,我们覆盖了原型属性 name,这意味着所有通过 Person 实例化的对象的 name 属性都会变成 '李四'。但是需要注意的是,如果一个实例对象中也有 name 属性,则该属性会覆盖原型中的属性。
更改原型
除了覆盖原型属性,我们还可以更改原型结构。
function Person() {}
Person.prototype = {
job: '工程师',
sayJob: function() { console.log(this.job); }
};
var person1 = new Person();
person1.sayJob(); // 输出 "工程师"
在这个示例中,同样定义了一个构造函数 Person,但是在这里传入了一个新的原型对象,包含了 job 和 sayJob 方法。这意味着实例化的对象也将继承 job 和 sayJob 方法,可以通过 person1.sayJob() 输出。
需要注意的是,在更改原型时,一定要在将新的原型对象赋值给构造函数的 prototype 属性后,再创建实例化对象,否则新的原型结构不会继承到实例化对象中。
示例说明
示例 1
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function(){
console.log('My name is ' + this.name);
}
function Dog(name, color) {
Animal.call(this, name);
this.color = color;
}
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
Dog.prototype.sayColor = function() {
console.log('My color is ' + this.color);
}
var dog1=new Dog('Doggy', 'white');
dog1.sayName(); // 输出 "My name is Doggy"
dog1.sayColor(); // 输出 "My color is white"
在这个示例中,我们定义了一个 Animal 构造函数,其中包含 name 属性和 sayName 方法。然后定义了一个 Dog 构造函数,通过原型继承 Animal 构造函数。
在 Dog 构造函数中,首先通过 Animal.call(this, name) 继承父类构造函数中的属性,因为使用了 call 方法绑定了 this,所以此时 Dog 对象中的 name 属性变成了传入的 name。
之后通过 Dog.prototype = new Animal() 将 Dog 的原型对象指向 Animal 的实例化对象,这样 Dog 的原型对象就可以继承 Animal 中的属性和方法了。
最后,我们添加了 Dog 特有的方法 sayColor 和发出输出。
示例 2
function Animal(name) {
this.name = name;
}
Animal.prototype.sayName = function(){
console.log('My name is ' + this.name);
}
function Dog(name, color) {
Animal.call(this, name);
this.color = color;
}
Dog.prototype = Object.create(Animal.prototype, {
constructor: {
value: Dog,
enumerable: false,
writable: true,
configurable: true
}
});
Dog.prototype.sayColor = function() {
console.log('My color is ' + this.color);
}
var dog1=new Dog('Doggy', 'white');
dog1.sayName(); // 输出 "My name is Doggy"
dog1.sayColor(); // 输出 "My color is white"
这是上例中的另一种写法,使用了 Object.create() 方法继承 Animal 的原型对象,并且在修改 Dog 的原型对象时,指定了 constructor 属性的值和可枚举性。
需要注意的是,由于 constructor 的可枚举性被设置为 false,所以 Object.keys(Dog.prototype) 的结果不会包含 constructor。
总结
覆盖原型和更改原型是 JavaScript 中常见的操作,能够方便地扩展和修改对象的结构,改善代码的可读性和可维护性。但需要注意对原型结构和原型链的理解,以避免在操作中产生预期之外的行为。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈JavaScript 覆盖原型以及更改原型 - Python技术站