首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >流行的JavaScript继承模式

流行的JavaScript继承模式
EN

Stack Overflow用户
提问于 2009-10-30 00:41:24
回答 5查看 11.3K关注 0票数 16

我正在做一个TDD JavaScript上的ebook on GitHub,我想知道我是否遗漏了一些流行的继承模式。如果你知道任何其他的模式,我很想看看。他们应该具备以下条件:

  1. 时间测试-在实际应用中使用的
  2. 源代码应提供。应该尽可能地直截了当和学究。
  3. 当然是正确的和有效的。

我这样做的原因是,似乎JavaScript中的对象继承对我们中的许多人来说都很难理解。我的JavaScript继承章节基本上是对以下内容的学习帮助:克罗克福德的Good Parts和Zakas的面向网络开发人员的专业JavaScript。

以下是我到目前为止所掌握的模式:

代码语言:javascript
复制
// Pseudoclassical Inheritance
    function Animal(name) {
        this.name = name;
        this.arr = [1,2,3];
    };
    Animal.prototype = {
        constructor: Animal,
        whoAmI: function() { return "I am " + this.name + "!\n"; }
    };

    function Dog(name, breed) {
        this.name = name;
        this.breed = breed;
    };
    Dog.prototype = new Animal();
    Dog.prototype.getBreed = function() {
        return this.breed;
    };
    Dog.prototype.bark = function() {
        return 'ruff ruff';
    };

    // Combination Inheritance
    function Parent(name) {
        this.name = name;
        this.arr = [1,2,3];
    };
    Parent.prototype = {
        constructor: Parent,
        toString: function() { return "My name is " + this.name; }
    };
    function Child(name, age) {
        Parent.call(this, name);
        this.age = age;
    };

    Child.prototype = new Parent();

    Child.prototype.getAge = function() {
        return this.age;
    };

    // Prototypal Inheritance
    var helper = { // Thanks to Bob Vince for reminding me NOT to clobber Object!

        inherit: function(p) {
        NewObj = function(){};
        NewObj.prototype = p;
        return new NewObj(); 
        },
        inheritPrototype: function(subType, superType) {
        var prototype = helper.inherit(superType.prototype);
        prototype.constructor = subType;
        subType.prototype = prototype;
        }
    };

    function SubType(name, age) {
        Parent.call(this, name);
        this.age = age;    
    };
    //Child.prototype = new Parent();   // Gets replaced by:
    helper.inheritPrototype(SubType, Parent);  
    SubType.prototype.getAge = function() {
        return this.age;
    };

    // Functional - Durable Pattern
    function super_func(blueprint) { 
        var obj = {};
        obj.getName = function() { return blueprint.name; };
        obj.getAge  = function() { return blueprint.age; };
        obj.getFoo  = function() { return blueprint.foo; };
        obj.getBar  = function() { return blueprint.bar; };
        return obj;
    };
    function sub_func(blueprint) {
        blueprint.name = blueprint.name || "Crockford's Place";
        supr = super_func(blueprint);
        supr.coolAugment = function() { return "I give a fresh new perspective on things!" };
        return supr;    
    };

对于那些感兴趣的人,这里是jspec测试(抱歉,但Markdown或他们正在使用的任何东西会稍微破坏格式):

代码语言:javascript
复制
describe 'JavaScript Inheritance Tests'
    before_each
    animal = new Animal("Onyx")
    dog = new Dog("Sebastian", "Lab")

    person = { password : 'secret', toString : function(){ return '<Person>' } }
    stub(person, 'toString').and_return('Original toString method!')    
    end
    describe 'Pseudoclassical Inheritance Creation'
    it 'should create parent and child object using pseudoclassical inheritance'
        animal.constructor.should.eql Animal
        // dog.constructor.should.eql Dog // Nope: expected Animal to eql Dog
        dog.constructor.should.eql Animal 
        animal.should.be_a Animal 
        dog.should.be_a Animal
        // dog.should.be_a Dog // Nope! We severed the original prototype pointer and now point to Animal!
        dog.should.be_an_instance_of Animal
        dog.should.be_an_instance_of Dog 
        (animal instanceof Dog).should.be_false
    end
    it 'should behave such that child inherits methods and instance variables defined in parent'
        animal.whoAmI().should.match /I am Onyx.*/ 
        dog.whoAmI().should.match /Sebastian.*/
        animal.should.respond_to 'whoAmI'
        dog.should.respond_to 'whoAmI'
        dog.should.have_prop 'name'
    end
    it 'should behave such that methods and instance variables added to child are NOT available to parent'
        dog.bark().should.match /Ruff Ruff/i
        dog.should.have_property 'breed'
        dog.should.respond_to 'bark'
        // animal.should.have_prop 'breed' // Of course not!
        // animal.should.respond_to 'bark' // Of course not!
    end
    it 'should behave such that reference variables on the parent are "staticy" to all child instances'
        dog.arr.should.eql([1,2,3]) 
        dog.arr.push(4)
        dog.arr.should.eql([1,2,3,4]) 
        spike = new Dog("Spike", "Pitbull")
        spike.arr.should.eql([1,2,3,4]) 
        spike.arr.push(5)
        rover = new Dog("Rover", "German Sheppard")
        spike.arr.should.eql([1,2,3,4,5])
        rover.arr.should.eql([1,2,3,4,5])
        dog.arr.should.eql([1,2,3,4,5])
    end 
    end

    describe 'Combination Inheritance Solves Static Prototype Properties Issue'
    it 'should maintain separate state for each child object'
        child_1 = new Child("David", 21)
        child_2 = new Child("Peter", 32)
        child_1.arr.push(999)
        child_2.arr.push(333)
        child_1.arr.should.eql([1,2,3,999])
        child_2.arr.should.eql([1,2,3,333])
        child_1.getAge().should.eql 21
        child_1.should.be_a Parent
    end
    end

    describe 'Prototypal Inheritance'
    it 'should inherit properties from parent'
        person.toString().should.match /Original toString.*/i
        person.password.should.eql 'secret'
        joe = helper.inherit(person)
        joe.password.should.eql 'secret'
        joe.password = 'letmein'
        joe.password.should.eql 'letmein'
        person.password.should.eql 'secret'
    end
    end

    describe 'Parisitic Combination Inheritance'
    it 'should use inheritPrototype (to call parent constructor once) and still work as expected'
        sub = new SubType("Nicholas Zakas", 29)
        sub.toString().should.match /.*Nicholas Zakas/
        sub.getAge().should.eql 29
        charlie = new SubType("Charlie Brown", 69)
        charlie.arr.should.eql([1,2,3])
        charlie.arr.push(999)
        charlie.arr.should.eql([1,2,3,999])
        sub.arr.should.eql([1,2,3]) 
        sub.should.be_an_instance_of SubType
        charlie.should.be_an_instance_of SubType
        (sub instanceof SubType).should.eql true 
        (sub instanceof Parent).should.eql true 
    end
    end

    describe 'Functional Durable Inheritance'
    it 'should hide private variables'
        sup = new super_func( {name: "Superfly Douglas", age: 39, foo: "foo", bar: "bar"} )
        sup.getName().should.eql 'Superfly Douglas'
        sup.name.should.be_undefined
        sup.getAge().should.eql 39 
        sup.age.should.be_undefined
        sup.getFoo().should.eql 'foo'
        sup.foo.should.be_undefined
    end

    it 'should create a descendent object that inherits properties while maintaining privacy'
        sub = new sub_func( {name: "Submarine", age: 1, foo: "food", bar: "barfly"} )
        sub.getName().should.eql 'Submarine'
        sub.name.should.be_undefined
        sub.getAge().should.eql 1 
        sub.age.should.be_undefined
        sub.getFoo().should.eql 'food'
        sub.foo.should.be_undefined 
        sub.getBar().should.eql 'barfly'
        sub.bar.should.be_undefined 
        sub.coolAugment().should.match /.*fresh new perspective.*/
        //sub.should.be_an_instance_of super_func NOPE!
        //sub.should.be_an_instance_of sub_func   NOPE!
        sub.should.be_an_instance_of Object 
    end
    end

end

谢谢大家!哦,如果你想看看我的论文/书,我很乐意得到反馈:TDD JavaScript at GitHub repo

EN

回答 5

Stack Overflow用户

发布于 2009-10-30 00:55:31

有关摘要,请参阅How to "properly" create a custom object in JavaScript?。(既然我花了太多时间把它打出来,不妨把它链接起来!)

这一点:

Dog.prototype =新动物();

通常会被避免。你可以在示例/教程代码中看到它,但它是一个可怕的混乱,因为它将一个类建立在一个实例上,而一个实例是以错误的方式构造的:name是未定义的。任何更复杂的构造函数都会对这类事情感到不安。

Object.prototype.inherit=

是一种更好的构造方法,但将任何东西原型化为Object都被认为是非常糟糕的。它冒着将对象用作微不足道的映射并破坏其他代码的风险。你可以把这个辅助函数放在别的地方,例如。Function.prototype.subclass

prototype.constructor

就我个人而言,我倾向于避免,因为constructor在JavaScript中有一个特殊的含义(就像在火狐和其他浏览器中实现的那样;而不是IE的JScript),这个含义既不是constructor在这里做的,也不是你期望任何这样的属性做的;它令人困惑,而且几乎总是最好避免的。因此,如果在类系统中的实例中包含到构造函数的链接,我更愿意给它命名为其他名称。

票数 8
EN

Stack Overflow用户

发布于 2010-12-15 08:56:10

我以前公司的一位同事开发了一个类似于继承http://www.uselesspickles.com/class_library/的java库。我认为它比Rajendra的建议更性感,语法看起来更干净。

我写了一篇文章,演示了不同的方法来处理它,但要确保避免已知的不良实践。http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html,如果你不想下载一个库,而只是想复制粘贴一些代码,你可以改进这些代码来做你需要的事情。

票数 1
EN

Stack Overflow用户

发布于 2012-11-26 10:41:21

这里值得一提的是一个有趣的模式: JavaScript构造函数可以返回任何对象(这不是必须的)。可以创建一个构造函数,它返回一个代理对象,其中包含"real“实例对象的"real”方法的代理方法。这听起来可能很复杂,但并不复杂;以下是一段代码片段:

代码语言:javascript
复制
var MyClass = function() {
    var instanceObj = this;
    var proxyObj = {
        myPublicMethod: function() {
            return instanceObj.myPublicMethod.apply(instanceObj, arguments);
        }
    }
    return proxyObj;
};
MyClass.prototype = {
    _myPrivateMethod: function() {
        ...
    },
    myPublicMethod: function() {
        ...
    }
};

好的是,如果我们定义一个命名受保护方法的约定,就可以自动创建代理。我创建了一个小库来做这件事:http://idya.github.com/oolib/

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1645027

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档