js之各种继承(二)

原型继承

  • object.create()有两个参数,第一个是用作新对象原型的对象,第二个参数是可选项,是一个定义额外新属性的对象。
  • object.create()使得新创建的anotherPerson对象的__proto__指针指向person的原型对象
  • 需要注意的是,原型式继承中, 包含引用类型值的属性始终都会共享相应的值, 就像使用原型模式一样,无法实现复用
// 无第二个参数
var person = {
	friends : ["Van","Louis","Nick"]
};
var anotherPerson = Object.create(person);
anotherPerson.friends.push("Rob");
var yetAnotherPerson = Object.create(person);
yetAnotherPerson.friends.push("Style");
alert(person.friends);//"Van,Louis,Nick,Rob,Style"
// create第二个参数的使用方法
var person = {
	name : "Van"
};
var anotherPerson = Object.create(person, {
	name : {
		value : "Louis"
	}
});
alert(anotherPerson.name);//"Louis"

寄生式继承

  • 寄生式继承的思路与(寄生)构造函数和工厂模式类似, 即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象
  • 比起原型继承,它将类似于Object.create()object()函数及一些操作封装金一个函数中,外界直接调用它就仿佛继承了它原来的父类一样
var original = {
	friends : ["Van","Louis","Nick"]
};
// object() 对传入其中的对象执行了一次浅复制,整个函数的工作就是让一个对象的__proto__指针指向参数
function object(o){
	function F(){}
	F.prototype = o;
	return new F();
}
function createAnother(original){ // 创建一个函数封装这些过程
	var clone = object(original); // 通过调用object函数创建一个新对象
	clone.sayHi = function(){ // 以某种方式来增强这个对象
		alert("hi");
	};
	return clone;//返回这个对象
}
var clone = createAnother(original);
console.log(clone.friends);
clone.sayHi()

寄生组合式继承

  • 为了解决组合继承两次调用父类构造函数的弊端(第一次是在子类型构造函数内部,第二次是在创建子类型原型的时候)
  • 寄生组合式继承就是为了降低调用父类构造函数的开销而出现的
function extend(subClass,superClass){
	var prototype = object(superClass.prototype); // 创建对象
	prototype.constructor = subClass; // 增强对象
	subClass.prototype = prototype; // 指定对象
}
function Parent (name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green'];
}

Parent.prototype.getName = function () {
    console.log(this.name)
}

function Child (name, age) {
    Parent.call(this, name);
    this.age = age;
}
// object(o)方法的工作就是:
// 创建一个构造函数f
// 使该构造函数的prototype指针指向参数
// 创建f对象的一个实例,幷返回
// 在该函数调用完以后,f的构造函数便会销毁,所以整个函数的工作就是让一个对象的__proto__指针指向参数。
function object(o) { // 感觉相当于制作了一个parent的副本
    function F() {}
    F.prototype = o; // 继承了传入的参数,这段代码extend中为其传人的参数是parent.prototype
    return new F();
    // 通过构造一个介于 Parent 与 Child 之间的对象,并使该对象的 prototype 属性指向 Parent 的 prototype对象,
    // 来避开通过调用 Parent 构造函数的方式来产生一个 prototype 指向Parent prototype对象的对象。
}

function extend(child, parent) {
// 不直接child.prototype=parent.prototype呢?
// 原因 : 当我们想给 Child 的prototype里面添加共享属性或者方法时,如果其 prototype 指向的是 Parent 的 prototype,那么在 Child 的 prototype 里添加的属性和方法也会反映在 Parent 的 prototype 里面,
// 这明显是不合理的,这样做的后果是当我们只想使用 Parent 时,也能看见 Child 往里面扔的方法和属性。
// 所以需要每个构造函数都需要持有自己专用的prototype对象
    var prototype = object(parent.prototype); // 创建对象
    prototype.constructor = child; // 增强对象
    child.prototype = prototype; // 指向对象
}

extend(Child, Parent);
var child1 = new Child('kevin', '18');
console.log(child1);
  • object方法图解:

img

在该函数调用完以后,f的构造函数便会销毁,所以整个函数的工作就是让一个对象的__proto__指针指向参数

上一篇在js之各种继承(一)

发布了46 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yuanfangyoushan/article/details/99706451