将Prototype与“Namespace”一起用于现有对象

时间:2017-11-01 19:19:25

标签: javascript namespaces prototype

我希望实现以下目标。

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>

我可以找到span并调用此代码返回“test”

spanElement.testNS.testFunc()

我知道当我这么做时,一个函数会保留它的父级范围......

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

但是我试图稍微组织一下代码,并且当我添加它们时,函数来自哪里更明显,当我做一个普通的JSON对象时,我似乎找不到保留范围的方法将此范围抓取到_this: this它只返回“窗口”的全局范围。

3 个答案:

答案 0 :(得分:3)

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

您的方法不适合您的原因是使用testNS对象作为this调用函数。

如果使用testNSObject.defineProperty定义为具有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();
<span id="mySpan">Wah-hoo!</span>

更“流露”的方法是让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();
<span id="mySpan">Wah-hoo!</span>

答案 1 :(得分:1)

当您将某个功能称为foo.bar()时,this内的bar会引用foo。因此,如果您将该功能称为spanElement.testNS.testFunc(),则this会引用spanElement.testNS

_this: this,无效,因为this无法引用<span>元素。

要从spanElement访问testFunc,您可以将testNS实施为获取者

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

document.querySelector('span').testNS.testFunc();
&#13;
<span>foo</span>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

因为这是一个奇怪的要求,我写了一个相当奇怪的解决方案:-)
基本上,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");