javascript - 使用 extend 将对象添加到原型(prototype)

标签 javascript node.js

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

TypeError: Cannot read property 'ipInt' of undefined

只是没有意义。当我将对象复制到原型(prototype)时,它的行为就像实际上正在执行 setter/getter 一样。有没有办法复制它而不会出现这样的错误?

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;
}

第二次编辑

所以我做了更多的实验,并想出了另外两种似乎有效的方法。一个使用前面发布的扩展方法,另一个使用评论中指出的 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根本不是实例(没有创建实例),但实际上 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 复制“原封不动”的 getter循环和 Object.defineProperty .


至于您的编辑:那些 __xxx__函数是获取 getter/setter 函数而不执行它的丑陋方法。通常,传递一个函数就像 someFunction没有括号。但是,如果您使用 someGetter 访问它, setter/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
}

关于javascript - 使用 extend 将对象添加到原型(prototype),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7434343/

相关文章:

javascript - 带有 AngularJS CORS 的 IE9、IE8 返回 “Access is denied” - ASP.NET WebApi

node.js - 亚马逊 AWS Elastic Beanstalk NodeJS 应用程序

node.js - 使用 ASP.Net Core 应用程序填充 Angular 上的下拉列表时出现错误 TS2717

node.js - 带有 Yarn 工作区的 Firebase 函数

node.js - 如何使用conversation.list API获取Slack工作区中的所有 channel ?

node.js - 无法在 debian 上安装 node-libcurl

javascript - 超时一系列异步函数

Javascript 样式显示不工作

javascript - 在 jQuery 中减慢 location.reload()?

javascript - phonegap 中嵌套的 sqlite 事务