zoukankan      html  css  js  c++  java
  • 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的更高效和简洁。 

  • 相关阅读:
    bind函数(c++11)
    谓词
    lambda表达式(c++11)
    重载运算符
    sizeof新用法(c++11)
    引用限定符(c++11)
    this指针和const成员函数
    JavaScript for循环元素取下标问题
    Hbuider sass配置 webstorm scss配置
    检测对象是否拥有某一属性
  • 原文地址:https://www.cnblogs.com/wang-jing/p/3953823.html
Copyright © 2011-2022 走看看