js 面向对象 继承机制

根据w3cschool上的描述:共有3种继承方法(对象冒充,原型链,混合)

 

1、对象冒充:构造函数ClassA使用this关键字给所有属性和方法赋值,使ClassA构造函数成为ClassB的方法,调用。可实现多重继承。

注意:所有新属性和新方法都必须在删除新方法的代码行后定义,否则会覆盖父类的相关属性和方法,多重继承时存在同名问题。

原始:

function ClassA(sColor){
	this.color = sColor
	this.sayColor = function(){
		alert(this.color);
	};
};

function ClassB(sColor, sName){
	this.newMethod = ClassA;
	this.newMethod(sColor);
	delete this.newMethod;

        //新属性和方法
	this.name = sName;
	this.sayName = function(){
		alert(this.name);
	}
}

var objA = new ClassA('blue');
var objB = new ClassB('red', 'jack');

call():function对象的一个方法,它是ECMASript把对象冒充规范化的结果

function ClassB(sColor, sName) {
    //this.newMethod = ClassA;
    //this.newMethod(color);
    //delete this.newMethod;
    ClassA.call(this, sColor);

    this.name = sName;
    this.sayName = function () {
        alert(this.name);
    };
}

apple():与call类似,第二个参数是数组或arguments(参数对象,两个类中的参数顺序完全一致的话,才可以)

function ClassB(sColor, sName) {
    //this.newMethod = ClassA;
    //this.newMethod(color);
    //delete this.newMethod;
    ClassA.apply(this, new Array(sColor));

    this.name = sName;
    this.sayName = function () {
        alert(this.name);
    };
}

以上存在内存浪费的问题。那就是对于每个实例对象而言,属性和方法都是一样的,但是每次创建新的实例,都要为其分配新的内存空间,这样做就会降低性能,浪费空间,缺乏效率。

 

2、原型链:把ClassB的prototype属性设置成ClassA的实例。ClassA的构造函数不能传递参数。

注意:所有新属性和新方法都必须在删除新方法的代码行后定义,否则会覆盖父类的相关属性和方法:因为prototype属性被替换成了新对象,添加了新方法和属性的原始对象将被销毁。

对 ClassB 的所有实例,instanceof 为 ClassA 和 ClassB 都返回 true。对象冒充时不能这样(instanceof是讲类型的,而对象冒充是讲方法的。)。不支持多重继承。

//确保构造函数没有任何参数
function ClassA(){

}
//方法用原型链
ClassA.prototype.color = 'blue';
ClassA.prototype.sayColor = function(){
	alert(this.color);
}

function ClassB(){

}
//把 ClassB 的 prototype 属性设置成 ClassA 的实例
ClassB.prototype = new ClassA();

//新方法和属性
ClassB.prototype.name = '';
ClassB.prototype.sayName = function(){
	alert(this.name);
}

 

3、混合方式:对象冒充的缺点,每个子类都有与父类相同的方法,这样很占空间;而原型链,子类只是指向父类的方法。但是不能多重继承。所以需要结合起来:对象冒充继承属性;原型链继承方法。

通过对象冒充方式继承时,所有的成员方法都是指向this的,也就是说new之后,每个实例将都会拥有这个成员方法,并不是共用的,这就造成了大量的内存浪费。并且通过对象冒充的方式,无法继承通过prototype方式定义的变量和方法(与我想的一样)

//父类属性用构造函数
function ClassA(sColor) { this.color = sColor; } //不变的用原型链 ClassA.prototype.sayColor = function () { alert(this.color); }; //子类构造函数用对象冒充继承 function ClassB(sColor, sName) { ClassA.call(this, sColor); this.name = sName; } //方法用原型链继承 ClassB.prototype = new ClassA();
//
ClassB.prototype.constructor = ClassB //新方法写在最后 ClassB.prototype.sayName = function () { alert(this.name); };

 注意:所谓的新属性,在对象冒充中是this.name。在原型链中是prototype.name。

 

instanceof深入学习

(1)值类型:数值、布尔值、null、undefined。

(2)引用类型:对象、数组、函数。

instanceof为了弥补typeof的不足,作用:实例是否属于某种类型;实例是否属于它的父类型;

新概念:显示原型,隐式原型:新概念,哈哈

真难:http://www.ibm.com/developerworks/cn/web/1306_jiangjj_jsinstanceof/

 

http://www.alloyteam.com/2015/06/javascript-shu-ju-jie-gou-he-suan-fa-jian-shu-qian-yan/

继承有三种方式:

1、

之前提到的混合方式

2、YUI继承

function Animal() {}
Animal.prototype.feeling = 'happy';
 
function extend(Child, Parent) {
    var F = function(){};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;
}
 
extend(Dog, Animal);
 
var dog = new Dog('二狗', '哈士奇');
print(dog.feeling); // happy

3、jquery继承

function Animal() {}
Animal.prototype.feeling = 'happy';
 
function deepCopy(Child, Parent) {
    var p = Parent.prototype;
    var c = Child.prototype;
    for (var i in p) {
        if (typeof p[i] === 'object') {
            c[i] = (p[i].constructor === Array) ? [] : {};
            deepCopy(p[i], c[i]);
        } else {
            c[i] = p[i];
        }
    }
}
 
deepCopy(Dog, Animal);
 
var dog = new Dog('二狗', '哈士奇');
print(dog.feeling); // happy

看情况用吧。

 

明白了

混合继承时,为什么要加:ClassB.prototype.constructor = ClassB

这篇教程写的很好,自己现在记录一下:http://www.jb51.net/article/22334.htm

重新覆盖prototype后,这条链上的对象和方法的constructor都变为object,为了纠正,需要把constructor重新定义。

 

对象继承 一般用混合方式比较好,w3cschool上的例子很清楚。 

YUI的更高效和简洁。 

posted on 2014-09-03 15:36  j.w  阅读(297)  评论(0编辑  收藏  举报