2

我正在尝试为模仿Crockford的 Javascript 类开发一个简单的寄生接口,我想实现一些基本的内省方法。给定下面的类,我该如何编写正确识别对象类的方法class_nameis_a

function Parent(name) {
    var self = {};
    self.name = name;

    self.init = function() {
        console.debug('init', self);
        return self;
    };

    self.ama = function() {
        return "AMA Parent named " + self.name;
    };

    // Introspective methods
    self.class_name = function() {
        // returns class name as a string
    };

    self.is_a = function(obj_class) {
        // returns boolean indicating whether object is instance of obj_class
    };

    self = self.init();
    return self;
}

function Child(name) {  
    var self = new Parent(name);

    var base_ama = self.ama;
    self.ama = function() {
        var ama = base_ama();
        return ama + ". NOT!";
    };

    self.init();
    return self;
}

以下是预计将通过的测试:

var alice = new Parent('Alice');
assert_equal(alice.name, 'Alice');
assert_equal(alice.class_name(), 'Parent');
assert(alice.is_a(Parent));
assert_not(alice.is_a(Child));
assert_equal(alice.ama(), 'AMA Parent named Alice');

var bob = new Child('Bob');
assert_equal(bob.class_name(), 'Child');
assert_not(bob.is_a(Parent));
assert(bob.is_a(Child));
assert_equal(bob.ama(), 'AMA Parent named Bob. NOT!');

你可以在这里找到一个带有测试设置的小提琴:

http://jsfiddle.net/LTfVa/3/

4

1 回答 1

2

原型继承高效、节省内存、相对简单且符合 Javascript 的特性。在我看来,寄生继承不是这些东西:

// extend:
// receiverCtor - A constructor function that we want to extend with another constructor's behavior
// supplierCtor - The supplier of the other constructor's behavior
// receiverProperties - Any instance methods/properties you want to push onto the receiver's prototype
// receiverStatics - Any methods/properties you want to attach to the constructor function itself
//
function extend(receiverCtor, supplierCtor, receiverProperties, receiverStatics) {
    receiverProperties = receiverProperties || {};
    receiverStatics = receiverStatics || {};

    var supplierProto = supplierCtor.prototype,
        receiverProto = Object.create(supplierProto),
        prop;

    receiverCtor.prototype = receiverProto;
    receiverProto.constructor = receiverCtor;
    receiverCtor.parent = supplierProto;

    if(supplierCtor !== Object && supplierProto.constructo === Object.prototype.constructor) {
        supplierProto.constructor = supplierCtor;
    }

    for(prop in receiverProperties) {
        if(receiverProperties.hasOwnProperty(prop)) {
            receiverProto[prop] = receiverProperties[prop];
        }
    }

    for(prop in receiverStatics) {
        if(receiverStatics.hasOwnProperty(prop)) {
            receiverCtor[prop] = receiverStatics[prop];
        }
    }
}

function Parent(name) {
    this.name = name;
}

function Child(name) {
    Child.parent.constructor.apply(this, arguments);
}

extend(Child, Parent);

var alice = new Parent('alice');
var bob = new Child('bob');

console.log(alice instanceof Parent);
console.log(!(alice instanceof Child));
console.log(alice.name == 'alice');

console.log(bob instanceof Parent); // inherits from parent
console.log(bob.constructor !== Parent); // but it isn't a parent
console.log(bob instanceof Child);
console.log(bob.constructor === Child);
console.log(bob.name === 'bob');

这是一个用于验证的 jsbin

编辑:该extend函数是在以下非常简单的关系之上的语法糖的集合:

function Parent(name) {
    this.name = name;
}

function Child(name) {
    Parent.apply(this, arguments);
}

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

以上十行将通过第一个示例中的所有测试。

于 2013-09-20T18:35:41.507 回答