【问题标题】:Using Prototype with "Namespace" for existing object对现有对象使用带有“命名空间”的原型
【发布时间】:2018-04-14 04:49:53
【问题描述】:

我希望实现以下目标。

HTMLSpanElement.prototype.testNS = {
  _this: this,
  testFunc: function() {
    console.log(this.innerHTML)  //undefined as expected as this is the testFunc object
  },
  testFunc2: function() {
    console.log(this._this) //Window object
  }
}

在这种情况下,我的目标是直接向 span 元素添加一些辅助函数。

所以,如果我有以下情况:

<span>test</span>

我可以找到跨度并调用此代码以返回“测试”

spanElement.testNS.testFunc()

我知道当我这样做时,函数会保留其父级的范围......

HTMLSpanElement.prototype.testFunc = function() {
   console.log(this.innerHTML)
}

但是我正在尝试稍微组织代码,并在添加函数时更清楚地显示函数的来源,当我执行普通 JSON 对象时,我似乎无法找到保留范围的方法将 this 作用域抓取到 _this: this 中,它只返回“window”的全局作用域。

【问题讨论】:

  • “因为这是 testFunc 对象” this 永远不会引用函数对象本身。如果调用函数为spanElement.testNS.testFunc(),则引用panElement.testNS

标签: javascript namespaces prototype


【解决方案1】:

免责声明:您不应尝试修改内置类型的原型,尤其是宿主对象。这是个坏主意。


您的方法对您不起作用的原因是函数被调用时使用 testNS 对象作为 this

如果您使用Object.definePropertytestNS 定义为具有getter 函数的属性,则可以使其工作。这样做的原因是 get 函数在访问属性的对象的上下文中运行(这将是跨度):

Object.defineProperty(HTMLSpanElement.prototype, 'testNS', { 
  get: function() {
    var _this = this;
    return {
      testFunc: function() {
        console.log(_this.innerHTML)
      },
      testFunc2: function() {
        console.log(_this)
      }
    }
  }
});
var span = document.getElementById('mySpan');

span.testNS.testFunc();
span.testNS.testFunc2();
&lt;span id="mySpan"&gt;Wah-hoo!&lt;/span&gt;

一种更“普通”的方法是让testNS 成为一个普通函数并像调用它一样调用它。这是因为 testNS 是在调用它的对象的上下文中调用的(同样是跨度):

HTMLSpanElement.prototype.testNS = function() {
  var _this = this;
  return {
    testFunc: function() {
      console.log(_this.innerHTML)
    },
    testFunc2: function() {
      console.log(_this)
    }
  }
}

var span = document.getElementById('mySpan');

span.testNS().testFunc();
span.testNS().testFunc2();
&lt;span id="mySpan"&gt;Wah-hoo!&lt;/span&gt;

【讨论】:

  • 嘿,我们可以使用 Object.create() 来做到这一点
  • @AnkitPandey 恐怕我不明白你在问什么。
  • 其实我正在尝试像 HTMLSpanElement.prototype.testNS = Object.create() 在创建我想把 {testFunc: function()...}
  • 我同意,我认为我不应该使用内置类型,使用内置类型的示例而不是粘贴大量代码更容易。我会看看这些例子,我知道我可以做双重功能,我只是想学习如何保持范围。
  • @AnkitPandey 我想不出办法让这个工作在这里。
【解决方案2】:

当您将函数调用为foo.bar() 时,this 内部的bar 指的是foo。因此,如果您将函数称为spanElement.testNS.testFunc(),则this 指的是spanElement.testNS

_this: this, 无法工作,因为 this 无法引用 &lt;span&gt; 元素。

要从testFunc 访问spanElement,您可以将testNS 实现为getter

Object.defineProperty(HTMLSpanElement.prototype, 'testNS', {
  get: function() {
    var element = this;
    return {
      testFunc: function() {
        console.log(element.innerHTML);
      },
    };
  },
});

document.querySelector('span').testNS.testFunc();
&lt;span&gt;foo&lt;/span&gt;

【讨论】:

    【解决方案3】:

    因为这是一个奇怪的要求,所以我写了一个等效的奇怪解决方案:-)
    基本上 createElement 已被覆盖,以便添加命名空间对象字面量,然后使用绑定到函数的元素实例在命名空间之上定义一个新函数 testFunc

    !function(){
        var defaultNamespace = "testNS";
        var createElement = document.createElement;
    
        document.createElement = function(tag, namespace) {
            var element = createElement.apply(document, arguments);
    
            element[namespace || defaultNamespace] = {
                testFunc : function() {
                    console.log(this.innerHTML);
                }.bind(element)
            };
    
            return element; 
        }    
    }();
    
    var span = document.createElement("span"); 
    

    【讨论】:

    • 这有点奇怪,我比什么都好奇,我正在尝试更多地了解 javascript 中的作用域,我正在玩弄它。
    猜你喜欢
    • 2011-10-31
    • 2020-05-17
    • 2014-04-25
    • 2010-12-23
    • 2015-04-09
    • 2017-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多