原型的继承
1.原型继承的方法
1.运用原型的原型__proto__
function Text(name) {
this.name = name;
}
Text.prototype.show = function () {
console.log(this.name);
};
function Text2(name) {
this.name = name;
}
let a = new Text2("橘子");
Text2.prototype.__proto__ = Text.prototype;
a.show();
同样的也可以使用专业方法来实现赋值Object.setPrototypeOf(Text2.prototype.__proto__,Text.prototype);
将构造函数Text的原型赋值给Text2原型的原型,这Text2的原型链上就有Text的原型我们就可以使用a访问到show函数,原型链如下图
图中Text2原型的原型被Text的原型所代替即a的原型链为-Text2的原型-Text的原型-Text原型的原型-NULL,所以a实例可以访问到show方法打印出橘子
- 运用Object.creat()方法
function Text(name) {
this.name = name;
}
Text.prototype.show = function () {
console.log("show");
};
function Text2() {
this.name = name;
}
Text2.prototype = Object.create(Text.prototype);
Text2.prototype.show2 = function () {
console.log("show2");
};
let a = new Text2();
a.show2();
使用Object.creat()方法新建了一个对象,将新对象的原型设置为Text的原型,这里需要注意的是,创建了新对象再添加了show2方法而且实例化a对象是在创建对象之后,使用a.show和a.show2都可以正常运行
2.原型继承带来的问题和解决方法
- 在使用第二种方法时,会丢失掉constructor属性,如果使用
console.log(Text2.prototype.constructor);
来访问不会报错但会找到Text,和想找到Text2就差之甚远了
怎么解决呢?
只需要给他添加上constructor属性并赋值为Text2就好啦,如下
Text2.prototype.constructor = Text2;
- 接1的背景,使用for in循环遍历对象时会查找原型链中的属性,所以当我们遍历a实例时会遍历出来如下图的结果
实际操作中并不希望将constructor属性遍历出来解决办法如下:
// Text2.prototype.constructor = Text2; //注意这里将第一个问题的解决方法注掉了
Object.defineProperty(Text2.prototype, "constructor", {
value: Text2,
enumerable: false,
});
这个解决办法显然是第一个办法的改进版本。
在文末再谈一下__proto__
let text = {};
text.__proto__ = {
show() {
console.log("橘子");
},
};
text.show();
text.__proto__ = "大兔子";
text.show();
以上代码会输出两个橘子,明明在我倒数第二行的时候,我改变了他的原型啊,为什么结果还会是两个橘子呢?
let text = {
action: {},
get __proto__() {
return this.action;
},
set __proto__(obj) {
if (obj instanceof Object) {
this.action = obj;
}
},
};
就是上面的原因啦,因为他是个 getter 和setter 会对输入的值进行判断,但是我就是想改变text.__proto__的值那我该如何操作呢?让对象不继承Object.prototype就行了没错,就是下面的方法,
let text = Object.create(null);
text.__proto__ = 99;
console.dir(text.__proto__);
好了今天的原型继承知识就告一段落了 Bye~~