使用extend将对象添加到原型中

时间:2011-09-15 16:34:13

标签: javascript node.js

每当我尝试将对象BaseNet添加到IPv4Address.prototype时,我都会收到错误消息。错误:

  

TypeError:无法读取未定义的属性“ipInt”

只是没有意义。当我将对象复制到原型时,它的行为实际上正在被执行。有没有办法复制这个并没有得到这样的错误?

var _s = require('underscore')

var BaseNet = {
  get network(){ 
    return new IPv4Address((this.ipInt & this.netmask.ipInt) >>> 0);
  },
}

function IPv4Address (address){
  this.ipInt = address
  this.netmask = {}
  this.netmask.ipInt = 255
}

_s.extend(IPv4Address.prototype,BaseNet)

//also fails with generic extend:

function extend(destination, source) {
  for (var k in source) {
    if (source.hasOwnProperty(k)) {
      destination[k] = source[k];
    }
  }
  return destination;
}

extend(IPv4Address.prototype,BaseNet)

首次修改

也许这是我自己问题的答案。 Resig有一个帖子,这个“修改后的”扩展方法似乎正在寻找我正在寻找的东西。谁能解释一下?这似乎是一个范围问题,但我不明白为什么它的行为就像有人在扩展操作期间实际上调用了getter。

http://ejohn.org/blog/javascript-getters-and-setters/

function extend(a,b) {
    for ( var i in b ) {
        var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);

        if ( g || s ) {
            if ( g )
                a.__defineGetter__(i, g);
            if ( s )
                a.__defineSetter__(i, s);
         } else
             a[i] = b[i];
    }
    return a;
}

第二次修改

所以我做了一些实验,我提出了另外两种似乎有用的方法。一个使用前面发布的extend方法,另一个使用defineProperties方法形成注释中指出的ECMA规范。这个比那个好吗?似乎“mixin”风格更适合我正在寻找的东西,但Object.create方式也有效。

var BaseNet = {}
Object.defineProperties(BaseNet, {
  "network":{
    enumerable:true,
    get: function (){return new IPv4Address((this.ipInt & this.netmask.ipInt) >>> 0)}
            }
    });

function IPv4Address (address){
  this.ipInt = address
  this.netmask = {}
  this.netmask.ipInt = 255
}
IPv4Address.prototype = Object.create(BaseNet)
var ip = new IPv4Address(12345)
ip.netmask

或者,您也可以这样做:

var BaseNet = {}
Object.defineProperties(BaseNet, {
  "network":{
    enumerable:true,
    get: function (){return new IPv4Address((this.ipInt & this.netmask.ipInt) >>> 0)}
            }
    });

function IPv4Address (address){
  this.ipInt = address
  this.netmask = {}
  this.netmask.ipInt = 255
}
extend(IPv4Address.prototype,BaseNet)
var ip = new IPv4Address(12345)
ip.netmask

1 个答案:

答案 0 :(得分:2)

它不起作用,因为在扩展时,执行getter,此时this.netmask根本不是实例(没有创建实例),但事实上undefined,所以访问{ {1}}引发错误(您无法从this.netmask.ipIntundefined访问任何,它会在任何情况下都会引发错误。)

查看基础null代码:

_.extend

您可能希望自己进行迭代,并使用 _.extend = function(obj) { each(slice.call(arguments, 1), function(source) { for (var prop in source) { // source[prop] is fetched, so getter is executed if (source[prop] !== void 0) obj[prop] = source[prop]; } }); return obj; }; 循环和for in复制“未触动”的getter。


至于你的编辑:那些Object.defineProperty函数是获取getter / setter函数而不执行它的一种丑陋方式。通常,传递函数的工作方式类似于__xxx__而没有括号。但是,如果使用someFunction访问它,则会自动执行getter。

您发布的功能会复制getter / setter而不执行它们:

someGetter