使用扩展将对象添加到原型

每当我尝试将对象BaseNet添加到IPv4Address.prototype时,都会收到错误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对此有一个post,这个“修改”的扩展方法似乎做我在找什么。 有人可以解释吗? 这似乎是一个范围的问题,但我不明白为什么它的行为就像有人在扩展操作中实际调用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; } 

第二编辑

所以我做了一些更多的尝试,并且提出了另外两种似乎可行的方法。 一个使用之前发布的扩展方法,另一个使用注释中指出的ECMA规范的defineProperties方法。 这个比那个好吗? 看起来,“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 

这是行不通的,因为在扩展时,getter被执行,在这一点上this.netmask根本不是一个实例(没有实例创build),但实际上undefined ,所以访问this.netmask.ipInt抛出一个错误(你无法访问undefinednull中的任何内容,无论如何抛出错误)。

看看底层的_.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循环”和“ Object.defineProperty ”复制getter“untouched”。


至于你的编辑:那些__xxx__函数是一个丑陋的方式来获取getter / setter函数而不执行它。 通常情况下,传递一个函数就像someFunction没有括号的函数一样工作。 但是,如果你使用someGetter访问getter,getter会自动执行。

你发布的函数拷贝getters / setters而不执行它们:

 function extend(a,b) { for ( var i in b ) { // iterate over all properties // get getter and setter functions var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i); if ( g || s ) { // if there is a getter or setter if ( g ) a.__defineGetter__(i, g); // copy getter to new object if ( s ) a.__defineSetter__(i, s); // copy setter to new object } else // if there is not getter nor setter a[i] = b[i]; // just copy the value; nothing special } return a; // return the altered object }