今天继续讨论javascript的继承
原型式继承
这种继承方式没有使用严格意义上的构造函数,借助原型还可以基于已有的对象创建新对象,同时还不必因此创建自定义类型
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
在object函数内部,先创建一个临时性的构造函数F,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。
本质上来说,object对传入其中的对象执行了一次浅复制。
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
const hqg = {
name: "洪七公",
skill: ['降龙十八掌', '打狗棒']
}
const gj = object(hqg);
gj.name = '郭靖';
gj.skill.push('九阴真经')
const hr = object(hqg);
hr.name = '黄蓉';
hr.skill.push('落英神剑掌');
console.log(gj);
console.log(hr);
console.log(hqg);
这种模式要去你必须有一个对象作为另一个对象的基础。
在这个例子中,hqg作为另一个对象的基础,把hqg传入object中,该函数就会返回一个新的对象。
这个新对象将hqg作为原型,所以它的原型中就包含一个基本类型和一个引用类型。
所以意味着如果还有另外一个对象关联了hqg,gj和hr修改数组skill的时候,也会体现在这个对象中。
实际上就相当于创建了hqg对象的两个副本
ES5新增Object.create规范了原型式继承
Object.create
Object.create这是什么?
先简单了解一下
object.create() 是使用指定的原型proto对象及其属性propertiesObject去创建一个新的对象。
Object.create(proto,propertiesObject)
proto 是必填参数,就是新创建出来的对象的原型 (新对象的 __proto__属性指向的对象),值得注意的是当proto为null的时候创建的新对象完全是一个空对象,没有原型,也就是没有继承Object.prototype上的方法。(如hasOwnProperty() toString() 等)
console.log(Object.create(null));//这么创建出来的对象特别干净
console.log(new Object());//做比较
console.log({});//做比较
const a = {};
const b = new Object()
const c = Object.create(Object.prototype);
propertiesObject是可选参数,作用就是给新对象添加新属性以及描述器,需要注意的是新添加的属性是新对象自身具有的属性也就是通过hasOwnProperty() 方法可以获取到的属性,而不是添加在原型对象里。
第二个是可选参数具体可以看这里
不展开讨论
看一个栗子,重点看gj.favourite
const hqg = {
name: "洪七公",
skill: ['降龙十八掌']
};
const gj = Object.create(hqg, {
favourite: {
value: "吃", //favourite 属性值
writable: true //属性可写
}
});
gj.name = "郭靖"
gj.skill.push('九阴真经')
gj.favourite = "睡觉"
console.log(gj.favourite);//=>睡觉
const hqg = {
name: "洪七公",
skill: ['降龙十八掌']
};
const gj = Object.create(hqg, {
favourite: {
value: "吃", //favourite 属性值
writable: false //属性不可写
}
});
gj.name = "郭靖"
gj.skill.push('九阴真经')
gj.favourite = "睡觉"
console.log(gj.favourite);//=>吃
favourite下属性还有很多,不再一一列举,可参看这里查看
区别
- Object.cerate()继承指定对象
- new Object() 继承内置对象Object
- 可以通过Object.create(null) 创建一个干净的对象,也就是没有原型,而 new Object() 创建的对象是 Object的实例,原型永远指向Object.prototype。
寄生式继承
寄生式继承是与原型式继承紧密相关的一种思路,它创造一个仅用于封装继承过程的函数,在函数内部以某种方式增强对象,最后再返回对象。
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function hero(params) {
const clone = object(params) //通过调用函数创建一个新对象
clone.sayHi = () => {
console.log('hi');
}
return clone
}
const hqg = {
name: "洪七公",
skill: ['降龙十八掌', '打狗棒']
}
const gj = hero(hqg);
gj.name = '郭靖';
gj.skill.push('九阴真经')
console.log(gj);
寄生组合式继承
组合继承有个弊端就是会调用两次被继承者的构造函数,解决方法就是使用寄生组合式继承。这又是什么呢?这个相对之前的比较复杂,但是高效的一点是只调用一次被继承者构造函数,原理就是通过寄生方式创建一个被继承者的副本,副本和被继承者共用一个prototype,这样就解决了之前的问题
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
function hero(Children, Hqg) {
const proto = object(Hqg.prototype); //返回Hqg的一个副本
proto.constructer = Children; //设置constructor指向, 因为新副本的原型对象被重写
Children.prototype = proto; //副本作为sub的原型对象
}
function Hqg() {
this.name = '洪七公';
}
Hqg.prototype.show = function () {
console.log(this.name);
}
function Gj() {
Hqg.call(this);
this.name = '郭靖'
}
function Hr() {
Hqg.call(this);
this.name = '黄蓉'
}
hero(Gj, Hqg);
hero(Hr, Hqg);
const gj = new Gj();
const hr = new Hr();
gj.show(); // =>郭靖
hr.show(); //=> 黄蓉
继承,这回没人说我是脚本了吧 😉