【问题标题】:Returning element on function without losing prototype在函数上返回元素而不丢失原型
【发布时间】:2013-11-03 16:37:51
【问题描述】:

任何人都知道如何创建一个返回元素而不丢失其原型的函数吗? 我正在尝试创建函数来创建新元素并将其作为元素返回。此函数将具有操作该元素的方法。当我返回该元素时,原型将不起作用。如果我不在该函数中使用return,原型可以正常工作,但函数返回this 对象。看这段代码:

function ObjEl(tagName, id) {
    'use strict';
    this.node = document.createElement(tagName);
    if (typeof id === 'string' && id.match(/^[a-zA-Z\d\_\-]+$/)) {
        this.node.setAttribute('id', id);
    }

    // return this.node;
}

ObjEl.prototype.atr = function (key, val) {
    'use strict';
    this.node.setAttribute(key, val);
    return this;
};

如果我取消注释 return this.node;,当我调用 test = ObjEl('div', 'test'); 时,它会返回 <div id="test"></div>,但此代码不起作用:

test = ObjEl('div', 'test').remove();

【问题讨论】:

  • 好吧,你根本做不到。您不能返回一个对象并期望它表现得像另一个对象。
  • 你不能那样做。你可以做的是在ObjEl.prototype 上重新创建一个元素的所有属性,但这只是另一个 jQuery,不要这样做。真的。
  • @minitech:是的,我知道 jQuery,目前我正在使用 Zepto。但是我想创建自己的库,并且功能与 jQuery 或 Zepto 不同。那么,你能告诉我如何重新创建原型吗?谢谢。 :)

标签: javascript prototypal-inheritance


【解决方案1】:

看起来很奇怪,但这能达到你想要做的吗?

var ObjEl=function ObjEl(tagName, id) {
    'use strict';
    this.node = document.createElement(tagName);
    if (typeof id === 'string' && id.match(/^[a-zA-Z\d\_\-]+$/)) {
        this.node.setAttribute('id', id);
    }

    // return this.node;
}

ObjEl.prototype.atr = function (key, val) {
    'use strict';
    this.node.setAttribute(key, val);
    return this;
};
var oldObjEl=ObjEl;
ObjEl=function (){
  return new oldObjEl(arguments[0],arguments[1]);
}

【讨论】:

  • 这是非常错误的。函数不应该是对象的原型。无论您最终尝试做什么,它都不会满足 OP 的要求。
  • 对,最后一行是错误的。我删除了它。没有它,我已经测试了这个函数,它通过了他在 OP 中提到的要求。可以使用额外的原型链来使对象也通过test instanceof ObjEl
【解决方案2】:

可能的选择

使用 JavaScript 实现这种行为的两种最佳方法(我知道)是创建一个包装对象,在内部管理您与相关元素的处理,即类似的东西到 jQuery(见下文);或使用您想要的附加功能直接扩展每个元素 DOM 节点。例如:

var extend = function( elm ){
  elm.attr = extend.attr;
};
extend.attr = function(){
  // your code here
};
var elm = extend(document.getElementById('div'));

可以添加到某些元素的源构造函数的原型,即HTMLElement,但这不会跨浏览器工作,并且可能会导致其他代码出现问题。与基本构造函数混淆通常是不受欢迎的。

我选择的方式

过去,我曾使用以下粗略的 sn-p 将多个不同的接口(选择性地)组合到同一个对象中。然而,它不是经验丰富的代码,并且可以从正确的设置和拆卸管理中受益匪浅——以避免内存泄漏的风险——因为它基本上只是一组闭包。

var harmony = function(){
  if( !(this instanceof harmony) ) { return new harmony(); }
};
harmony.prototype.borrow = function( owner, descriptor ){
  var i, dlen = descriptor.length, item;
  for ( i=0; i<dlen; i++ ) {
    if ( (item = owner[descriptor[i]]) && item.apply ){
      this.borrowMethod( owner, descriptor[i] );
    }
    else {
      this.borrowAttribute( owner, descriptor[i] );
    }
  }
  return this;
};
harmony.prototype.add = function( owner, methods ){
  for ( var i in methods ) { this.addMethod( owner, i, methods[i] ); }
  return this;
};
harmony.prototype.addMethod = function( owner, name, method ){
  this[name] = function(){ return method.apply( owner, arguments ); };
  return this;
};
harmony.prototype.borrowMethod = function( owner, name ){
  this[name] = function(){ return owner[name].apply( owner, arguments ); };
  return this;
};
harmony.prototype.borrowAttribute = function( owner, attributeName ){
  var self = this; self[attributeName] = function(){
    if ( arguments.length ) { owner[attributeName] = arguments[0]; return self; }
    return owner[attributeName];
  };
  return self;
};

用法

上面可以用来包装一个元素,从本地对象借用方法,并用你自己的方法进行扩展。这是我的意思的粗略概念,这绝不是最终的代码。

var ElementHarmony = function(elm){
  var self = harmony()
    .borrow( elm, ['innerHTML', 'getElementsByTagName'] )
    .add( elm, {
      getElement: function(){
        return elm;
      },
      attr: function( name, value ){
        if ( arguments.length > 1 ) {
          this.setAttribute( name, value );
          return self;
        }
        else {
          return this.getAttribute( name );
        }
      }
    })
  ;
  return self;
}
/// create our example element and wrap with a harmony instance
var elm = ElementHarmony(document.createElement('span'))
  .innerHTML('<b>hello</b>')
  .attr('style', 'border: 1px solid red')
;
/// find the bold tag inside, and modify it's style
var bold = ElementHarmony(elm.getElementsByTagName('b')[0])
  .attr('style', 'background: orange')
;
/// use getElement() to get back to the original element,
/// when passing to native methods.
(document.body||document.documentElement).appendChild(elm.getElement());

使用和谐对象,您可以从所有者对象中借用方法和属性,但是属性会转换为方法,即innerHTML()。如果您知道您的代码只会在现代浏览器上执行,您可以更改此行为以利用 getter 和 setter...但是,那就是另一回事了。

嘿骗子骗子

这是小提琴。

http://jsfiddle.net/K2Xux/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-07
    • 2016-04-05
    • 2011-05-26
    • 1970-01-01
    • 2020-07-02
    • 1970-01-01
    相关资源
    最近更新 更多