Javascript中怎么实现继承?

传统的继承:

var Person = function (name) {

    this.name = name || "default name";

    if (typeof Person._initialized == "undefined") {
        Person.prototype.getName = function () {
            return this.name;
        };
        Person._initialized = true;
    }
};

var Author = function (name, books) {
    Person.call(this, name);
    this.books = books || [];

    /*
    if (typeof Author._initialized == "undefined") {
        Author.prototype = new Person();
        Author.prototype.constructor = Author;
        Author.prototype.getBooks = function () {
            return this.books;
        };
        Author._initialized = true;
    }
    
*/
};
Author.prototype = new Person();
Author.prototype.constructor = Author;
Author.prototype.getBooks = function () {
    return this.books;
};


var p1 = new Person("zhangsan");
var p2 = new Person("lisi");
console.log(p1.getName());
console.log(p2.getName());

var a1 = new Author("Raymond", ["Pro Javascript Design Pattern", "Asp.net Framework"]);
var a2 = new Author("Rock", ["Oracle & PL SQL"]);
console.log(a1.getName());
console.log(a1.getBooks());
console.log(a2.getName());
console.log(a2.getBooks());

注意:注释的代码是我老喜欢用的动态原型。但是,很遗憾,它不能用在这里。因为,第一次调用Author构造函数执行到此处时,Author的实例对象已经被初始化了,改变Author的prototype已经不能对它形成影响(但是会对之后创建的Author对象实例起作用)。

      为了更加OOP,我们自己模拟一下extend关键字。具体如下:  

var extend = function (subClass, superClass) {

    var F = function () { };
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;

    subClass.superClass = superClass.prototype;
    if (superClass.prototype.constructor != superClass) {
        superClass.prototype.constructor = superClass;
    }
};

var Person = function (name) {
    this.name = name || "default name";

    if (typeof Person._initialized == "undefined") {
        Person.prototype.getName = function () {
            return this.name;
        };
        Person._initialized = true;
    }
};

var Author = function (name, books) {
    Author.superClass.constructor.call(this, name);
    this.books = books || [];
};
extend(Author, Person);
Author.prototype.getBooks = function () {
    return this.books;
};

     还有一种被称为:prototypal的方式: 

function clone(object) {

    function F() { }
    F.prototype = object;

    return new F();
}

var Person = {
    name: "default name",
    configure: function (name) {
        this.name = name;
    },
    getName: function () {
        return this.name;
    }
};

var Author = clone(Person);
Author.books = [];
Author.configure = function (name, books) {
    // Person.configure(name);
    this.name = name;
    this.books = books;
};
Author.getBooks = function () {
    return this.books;
};

这里对象类不再通过function实现,而是通过object literal。 因为没有构造器了,构造的实现迁移到configure方法中。遗憾的是,至今我仍没有找到合适的方法在Author类中override configure方法(被注释那一行),最后只能重复去赋值name。需要注意的是,这里author继承自Person的成员,在未被author重新创建(赋值)前,均通过prototype链指向的是对应于Person中的成员。虽然,书中提出用工厂方法来Person创建对象的成员,但我始终觉得它不是很合适,并且不能解决override的问题。

   最后一个就是Mixin了。如下: 

function augment(receivingClass, givingClass, isOverideExsitingMember, requestMemberArray) {
    if (requestMemberArray) {
        for (key in requestMemberArray) {
            var memberKey = requestMemberArray[key];
            if (givingClass.prototype[memberKey] && (isOverideExsitingMember || !receivingClass.prototype[memberKey])) {
                receivingClass.prototype[memberKey] = givingClass.prototype[memberKey];
            }
        }
    } else {
        for (memberKey in givingClass.prototype) {
            if (isOverideExsitingMember || !receivingClass.prototype[memberKey]) {
                receivingClass.prototype[memberKey] = givingClass.prototype[memberKey];
            }
        }
    }
}

var Person = function (name) {
    this.name = name || "default name";
};
Person.prototype.getName = function () {
    return this.name;
};

var Mixin = function () { };
Mixin.prototype = {
    serialize: function () {
        var output = [];
        for (key in this) {
            output.push(key + ':' + this[key]);
        };
        return output.join(',');
    },
    getName: function () {
        return "This is test method from Mixin.";
    }
};

augment(Person, Mixin, true);

var p1 = new Person("zhangsan");
var p2 = new Person("lisi");
alert(p1.getName());
console.log(p1.serialize());

其实,我觉得它更多的是一种组合的概念,而不是继承。

     这里讲了继承的主干概念外,其实还涉及到了extend、clone、augment的模拟实现,可以将方法独立拿去使用。download

原文地址:https://www.cnblogs.com/Langzi127/p/2683624.html