3

我有一个extend方法可以扩展对象,就像您在 JavaScript 中所期望的那样:

var objA = {a: true};
var objB = extend({b:false}, objA);
console.log(objB); // {a: true, b: false}

但是,我想通过引用将源的 ( objA) 属性扩展到目标 ( objB) 对象,以便对源所做的任何更改在事后反映在目标中,如下所示:

var objA = {a: true};
var objB = extend({b: false}, objA);
console.log(objB); // {a: true, b:false}
objA.a = false;
console.log(objB); // {a: false, b:false}

例如,当您修改一个对象(始终通过引用分配)时,事情正在按照我希望的方式工作:

var objA = {A:{a: true}};
var objB = _.extend({b: false}, objA);
console.log(objB) // {A:{a:true}, b:false};
objA.A.a = false; 
console.log(objB); // {A:{a:false}, b:false};

因此,换句话说,当对objA的非对象文字属性(或任何未通过引用分配的值)进行更改时,我希望这些更改反映在objB.

我相当确定如果没有额外的辅助方法,这完全不可能,该方法依赖于某种对象监视方法,该方法在对象更改时触发。

想法?

我的extend方法中的代码:

(l).extend = (l).merge = function () {
    var args = (l).fn.__args(arguments, [{
            deep: 'bool'
        }, {
            '*': 'obj:object'
        }
    ]),
        target = (l)._object || args.obj,
        keys = [],
        obj, objs, copy, key, i, o;

    // Collect potential objects to merge
    objs = (l).filter(args, function (value, index) {
        if (index !== "obj" &&
            (l).isPlainObject(value) && !((l).isEqual(target, value))) {
            return value;
        }
    });

    // When target object is not selected globally
    if (!args.obj) {
        target = objs.shift();
    }

    // When target object is not selected globally and only a single object
    // is passed extend the library itself
    if (!(l)._global && !objs.length) {
        target = this;
        objs[0] = args.obj;
    }

    // When a boolean is passed go deep
    if (args.deep) {

        // Build property reference used to prevent never ending loops
        (l).each(objs, function (index, value) {
            keys.push((l).keys(value));
            keys = (l).flatten(keys);
        });

        // Add properties to all nested objects
        (l).deep(target, function (depth, index, obj, ref) {
            if ((l).indexOf(keys, index) === -1) {
                for (i = 0; i < objs.length; i++) {
                    for (key in objs[i]) {
                        if ((l).isPlainObject(obj)) {
                            copy = objs[i][key];
                            obj[key] = copy;
                        }
                    }
                }
            }
        }, "*");
    }

    // Merge first level properties after going deep
    for (i = 0; i < objs.length; i++) {
        if ((obj = objs[i]) !== null) {
            for (key in obj) {
                copy = obj[key];
                if (target === copy) {
                    continue;
                }
                target[key] = copy;
            }
        }
    }
    return (l).fn.__chain(target);
};
4

2 回答 2

3

你在这里提到的正是 JavaScript 的原型继承:

var objA = {a: false};
var objB = Object.create(objA);
objB.b = false;

console.log(objB.a, objB.b); // true, 
objA.a = false;
console.log(objB.a, objB.b); // false, false

当然如果objB重写a属性,你会失去那个链接,因为 JavaScript 会a在对象中找到属性objB,因此不会在原型链中查找。

使用 ECMAScript 5 方法,您可以拥有这样的extend功能:

function extend(properties, proto) {
  var object = Object.create(proto);
  var descriptor = {};

  Object.getOwnPropertyNames(properties).forEach(function(name) {
    descriptor[name] = Object.getOwnPropertyDescriptor(properties, name);
  });

  return Object.defineProperties(object, descriptor);
}


var objA = {a: true};
var objB = extend({b: false}, objA);
console.log(objB.a, objB.b); // true, false
objA.a = false;
console.log(objB.a, objB.b); // false, false
于 2013-04-06T00:34:18.760 回答
1
Object.extend= function (properties,obj) {
            function F() { };
            F.prototype = obj;
            var newObj = new F();
            for (var prop in properties){
                 newObj[prop] = properties[prop];
            }
            return newObj;
        }
于 2013-04-06T00:12:29.180 回答