我的JavaScript mixins函数有什么问题?

时间:2015-03-03 21:55:19

标签: javascript functional-programming mixins

我试图在JavaScript中为功能 mixin工作。

http://jsfiddle.net/xe207yec/3/

该函数应该从old创建一个新对象,将mixin对象的属性添加到它,并返回新对象 - 同时不改变旧对象,以便可以按预期使用它。

var plusMixin = function(oldObj, mixin) {
    var newObj = oldObj;
    newObj.prototype = Object.create(oldObj.prototype);
    for (var prop in mixin) {
        if (mixin.hasOwnProperty(prop)) {
            newObj.prototype[prop] = mixin[prop];
        }
    }
    return newObj;
};

但它没有用。问题是旧对象仍在变异。

知道为什么吗?谢谢!

3 个答案:

答案 0 :(得分:1)

您的代码不起作用,因为:

var newObj = oldObj;

这是一个简单的分配,意味着newObj现在指向与oldObj相同的对象。

newObj.prototype = Object.create(oldObj.prototype); 

这可能是也可能不是你想要的。如果oldObj是一个函数,那么这将起作用。如果oldObj不是一个函数(即一个普通的Object实例),那么这将不起作用,你将需要类似下面的代码:

var plusMixin = function(oldObj, mixin) {
    // Construct the [[Prototype]] for the new object
    var newObjPrototype = Object.create(Object.getPrototypeOf(oldObj));

    // Mix-in the mixin into the newly created object
    Object.keys(mixin).map(function(k) {
      newObjPrototype[k] = mixin[k];
    });

    // Use this newly created and mixed-in object as the [[Prototype]] for the result
    return Object.create(newObjPrototype);
};

<强>理由:

你想要一个原型链:

newObj --> newObj[[Prototype]] --> oldObj[[Prototype]]

然后,您希望将mixin混合到newObj[[Prototype]]中,使mixin(及其[[Prototype]]保持不变。

<强>用法:

function Foo() {};
Foo.prototype.hello = function() {}
function Bar() {};
Bar.prototype.goodbye = function() {}

var foo = new Foo();
var foobar = plusMixin(foo, Bar.prototype); // foobar now has hello and goodbye available to it

答案 1 :(得分:1)

@Dan - 与您的上一个答案和提供的小提琴引用一样...... http://jsfiddle.net/xe207yec/6/ ...由于第94,95行,代码示例未按预期记录。将其改为......

coffeeTypes = coffeeTypes.concat(peruvian);
coffeeSizes = coffeeSizes.concat(extraLarge);

......干得好。

我也抓住了机会,提供了一个额外的基于功能的混合组合方法,以便让整个事情自旋 - http://jsfiddle.net/xe207yec/8/

答案 2 :(得分:0)

我发现了什么是错的,所以我想回答我自己的问题。

首先我要说的是,这可能是一个奇怪的混合方式,所以不要相信我的话。

问题不在于我制作mixins的函数plusMixin,而是使用它的示例代码。如果你看一下问题中的jsfiddle,我就错误地创建了新的混合类。这是正确的用法:

// build new objects that are combinations of the above
// and put them into a new array
var coffees = coffeeTypes.reduce(function(previous, current) {
  var newCoffee = coffeeSizes.map(function(mixin) {
    // `plusMixin` function for functional mixins, see Ch.7
    var newCoffeeObj = plusMixin(current, mixin);
    return new newCoffeeObj();
  });
  return previous.concat(newCoffee);
},[]);

// we've now defined how to get the price and label for each
// coffee type and size combination, now we can just print them
coffees.forEach(function(coffee){
  printPrice(coffee.getPrice(), coffee.getLabel());
});

http://jsfiddle.net/xe207yec/6/