最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

JS中继承方式总结

XAMPP新闻 admin 1130浏览 0评论
 说在前面:
为了使代码更为简洁方便理解, 本文中的代码均将“非核心实现”部分的代码移出。

一、原型链方式
关于原型链,可点击《深入浅出,JS原型链的工作原理》,本文不再重复叙述。

思路:让构造函数的原型对象等于另一个构造函数原型对象的实例。

function A() {
}
A.prototype.fn = function (){
console.log(“in A”);
}

function B() {
}
B.prototype = new A();  // 让构造函数的原型对象等于另一个构造函数原型对象的实例

var b = new B();
b.fn(); // in A
console.log(b instanceof B); // true
console.log(b instanceof A); // true
console.log(b instanceof Object); // true
缺陷:1、如果父构造函数中的属性为引用类型,则会互现实例相互影响的情况;

function A() {
this.prop = [‘1’,”2″];
}
A.prototype.fn = function (){
console.log(this.prop);
}

function B() {
}
B.prototype = new A();  // 让构造函数的原型对象等于另一个构造函数原型对象的实例

var b1 = new B();
var b2 = new B();
b1.fn(); //  [“1”, “2”]
b2.fn(); //  [“1”, “2”]

b1.prop.push(‘3’);
b2.prop.push(‘4’);

b1.fn(); // [“1”, “2”, “3”, “4”]
b2.fn(); // [“1”, “2”, “3”, “4”]
二、借用构造函数方式
为了解决“原型链方式”继承的缺陷,引入的一种“继承”方案。

思路:通过call/apply,在子构造函数中调用父类的构造函数

function A() {
this.prop = [‘1’,”2″];

this.fn2 = function () {
console.log(this.prop);
}
}
A.prototype.fn = function (){
console.log(this.prop);
}

function B() {
A.call(this); // 通过call/apply,在子构造函数中调用父类的构造函数
}

var b1 = new B();
var b2 = new B();
b1.fn2(); // [“1”, “2”]
b2.fn2(); // [“1”, “2”]

b1.prop.push(‘3’);
b2.prop.push(‘4’);

b1.fn2(); // [“1”, “2”, “3”]
b2.fn2(); // [“1”, “2”, “4”]

b1.fn(); // 提示异常:b.fn is not a function
console.log(b1 instanceof B); // true
console.log(b1 instanceof A); // false
console.log(b1 instanceof Object); // true
缺陷:由于“继承”过程中,A仅充当普通函数被调用,使得父构造函数A原型无法与形成子构造函数B构成原形链关系。因此无法形成继承关系:”b1 instanceof A”结果为false,B的实例b1亦无法调用A原型中的方法,从实际意义上考虑,这种不属于继承。

三、组合继承
结合“原型链方式”和“借用构造函数方式”的有点,进行改进的一种继承方式。

思路:原型上的属性和方法通过“原型链方式”继承;构造函数内的属性和方法通过“借用构造函数方式”继承

function A() {
this.prop = [‘1’,”2″];
}
A.prototype.fn = function (){
console.log(this.prop);
}

function B() {
A.call(this); // 借用构造函数方式
}
B.prototype = new A(); // 原型链方式

var b1 = new B();
var b2 = new B();
b1.fn(); // [“1”, “2”]
b2.fn(); // [“1”, “2”]

b1.prop.push(‘3’);
b2.prop.push(‘4’);

b1.fn(); // [“1”, “2”, “3”]
b2.fn(); // [“1”, “2”, “4”]
console.log(b1 instanceof B); // true
console.log(b1 instanceof A); // true
console.log(b1 instanceof Object); // true
缺陷:子构造函数的原型出现一套冗余“父构造函数非原型上的属性和方法”。上述代码在执行“A.call(this);”时候,会给this(即将从B返回给b1赋值的对象)添加一个“prop”属性;在执行“B.prototype = new A();”时,又会通过实例化的形式给B的原型赋值一次“prop”属性。显然,由于实例属性方法的优先级高于原型上的属性方法,绝大多数情况下,原型上的“prop”是不会被访问到的。

四、寄生组合式继承
为了解决“组合继承”中子构造函数的原型链出现冗余的属性和方法,引入的一种继承方式。

思路:在组合继承的基础上,通过Object.create的方式实现原型链方式

function A() {
this.prop = [‘1’,”2″];
}
A.prototype.fn = function (){
console.log(this.prop);
}

function B() {
A.call(this);
}
B.prototype = Object.create(A.prototype); // Object.create的方式实现原型链方式

var b1 = new B();
var b2 = new B();
b1.fn(); // [“1”, “2”]
b2.fn(); // [“1”, “2”]

b1.prop.push(‘3’);
b2.prop.push(‘4’);

b1.fn(); // [“1”, “2”, “3”]
b2.fn(); // [“1”, “2”, “4”]

console.log(b1 instanceof B); // true
console.log(b1 instanceof A); // true
console.log(b1 instanceof Object); // true
最后补充
1、子构造函数的实例和原型的constructor属性指向父构造函数。为了与ECMAScript规范保持一致,在所有的“原型链继承”后,应当将原型的constructor属性指向子构造函数本身:

B.prototype = ….
–> B.prototype.constructor = B; <–

2、Object.create方法的功能是:将入参(需为一个对象)作为原型,创建并返回一个新的(只有原型属性和方法的)的对象。此功能等价于:

function object(o){
function F(){}
F. prototype = o;
return new F();
} // 来源于《JavaScript高级程序设计(第3版)》

转载请注明:XAMPP中文组官网 » JS中继承方式总结

您必须 登录 才能发表评论!