Javascript:对象返回自身,也称为链接

Javascript:对象返回自身,也称为链接,javascript,Javascript,我正在尝试构建自己的类似jquery的小库,但创建这种链接模式的过程非常艰难。基本上,我有一个类,其中包含一系列方法,可以更轻松地操作文档。这里有一个例子 function MF(selector){ var DO; // Stands for DocumentObject this.select = function(selector){ return document.getElementById(selector); } if(typeof

我正在尝试构建自己的类似jquery的小库,但创建这种链接模式的过程非常艰难。基本上,我有一个类,其中包含一系列方法,可以更轻松地操作文档。这里有一个例子

function MF(selector){
    var DO; // Stands for DocumentObject
    this.select = function(selector){
        return document.getElementById(selector);
    }
    if(typeof selector === 'string'){
        DO = this.select(selector);
    }else if(selector instanceof HTMLElement){
        DO = selector;
    }

    this.children = function children(selector){
        return DO.getElementsByClassName(selector);
    }
    return {
        MF: ???
    }
}(null);
我的想法可能是错误的,但我发现为了给文档对象(html元素)提供额外的方法,我需要扩展HtmleElement原型,或者将元素与类一起传递。我选择了第二种选择。我只是不知道在我的课堂上应该返回什么,这样我就可以进行链接了。在本例中,我的目标是能够编写以下代码行:

MF('someDiv').children('someClass');

在一次绝望的尝试中,我尝试返回一个
MF
的新实例,默认情况下,它不应该有实例,并导致我自己进入一个无限循环。我真的不知道我应该返回那里做什么。非常感谢您的帮助

返回这个将允许访问构造函数的方法。如果方法不需要返回另一个值,则在构造函数的最底层和属于它的每个方法的最底层执行此操作

function MF(selector){
  var doc = document;
  this.select = function(selector){
    return doc.getElementById(selector);
  }
  // there are problems with some of your code
  this.someMethod = function(){
    /* do stuff - If you want to access an Element then
      var thisIsNowGlobal = this.select('someId');
      thisIsNowGlobal.innerHTML = 'someText';
      Note, the keyword this is global not var
      If you wrote this.select('someId').innerHTML the property would not exist

      When a property of an Object is assigned to a variable or argument
      the this value changes to the global context.
   */
    return this;
  }
  return this;
}

看起来您也尝试过使用模块模式,但没有利用原型

当您想要链接某个对象时,您需要在可链接方法中返回自身(
this
),或者返回对象的
新实例。在下面的例子中,我通过使用新实例来实现链接(孩子们看起来需要一个列表,所以我做了一个数组)


你可以很容易地做到这一点。请记住,当
返回此
时,如果
上定义了方法,则可以按顺序调用它们

var MyUtilThing = function(){};
MyUtilThing.prototype.doStuff = function doStuff (){ // give it a name, helps in debugging
  // do your thing
  console.log('doing stuff');
  return this; // this is your instance of MyUtilThing
}

var thing = new MyUtilThing();
thing.doStuff().doStuff().doStuff(); // etc
避免显式创建实例的一种方法是在构造函数中这样做

var MyUtilThing = function(selector){
  var F = function(){};
  F.prototype = MyUtilThing.prototype;
  var toReturn = new F();
  toReturn.initialize(selector);
  return toReturn;
};

MyUtilThing.prototype.initialize = function initialize(selector){
  this.selector = selector;
};

MyUtilThing.prototype.doStuff = function doStuff (){ // give it a name, helps in debugging
  // do your thing
  console.log('doing stuff to', this.selector);
  return this; // this is your instance created in the constructor (the blank function with the same prototype as MyUtilThing)
}

var thing = MyUtilThing('div'); // no use of new here!
thing.doStuff().doStuff().doStuff(); // etc

但是,进入了一些稍微沉重的领域。最好的办法就是试着准确地理解这个
在JS中是如何使用的,你会有很长的路要走。

传统上jQuery启用链接的方式是为每种类型的返回值创建一个包装器对象。例如,在您的情况下,为
HTMLElement
创建自己的包装是值得的:

function HTMLElementWrapper(element) {
    if (element instanceof HTMLElementWrapper) return element;
    this.element = element;
}
现在您有了
htmlElementRapper
,您可以按如下方式重构
MF
函数:

function MF(selector) {
    return new HTMLElementWrapper(typeof selector === "string" ?
        document.getElementById(selector) : selector);
}
MF("someDiv").select("something").children("someClass");
MF
函数现在返回一个
HTMLElementWrapper
对象,该对象有两种方法
select
children

HTMLElementWrapper.prototype.select = function (selector) {
    return new HTMLElementWrapper(this.element.getElementById(selector));
};

HTMLElementWrapper.prototype.children = function (selector) {
    return new NodeListWrapper(this.element.getElementsByClassName(selector));
};
当然,要使
子函数
正常工作,您需要创建
节点列表包装器
构造函数:

function NodeListWrapper(list) {
    if (list instanceof NodeListWrapper) return list;
    this.list = list;
}
现在,您可以按如下方式链接方法:

function MF(selector) {
    return new HTMLElementWrapper(typeof selector === "string" ?
        document.getElementById(selector) : selector);
}
MF("someDiv").select("something").children("someClass");

要在
.children(“someClass”)
之后链接方法,您需要将这些方法添加到
NodeListWrapper.prototype

提示:
MF('someDiv')
应该返回一个对象和方法,而这些对象和方法不返回任何其他内容(与
.children
)应该返回
this
。默认情况下,如果没有显式返回对象,JavaScript中的构造函数将返回
this
。我想你是想
从不返回任何其他内容的方法中返回这个
。请看我上面的评论:我不明白,如果我在方法
select
中返回
this
,我该如何抓住HTML元素?@php\u nub\u qq:你需要像jQuery那样做,并将它们作为调用
MF
的结果的属性。如果我将
返回此
放在底部,和你一样,我得到的是window对象:/I我想这是因为我没有实例,但我如何才能返回singleton对象?@php\u nub\u qq关于你的最后一个问题。如果您想要HTML元素本身,您应该将object.property分配给一个变量,这样就可以返回到全局上下文中。这纯粹是一种惊奇。我唯一不明白的是,使用
原型
和将函数定义为
this.function
之间有什么区别,因为显然有。我认为如果构造函数只返回一个新实例,而不是检查MF
是否为
此实例,那么会更干净。类似于函数
MF(选择器){返回新的API(选择器);}
。允许
MF(mfObject)
@php\u nub\u qq I第二个plalx可能是个好主意。看看我的答案:构造函数中的@php\u nub\u qq设置方法具有创建新闭包的优势,这意味着您可以从构造函数访问
var
iable。然而,这也是一件坏事,因为这意味着您要多次创建相同的函数,消耗内存。使用原型意味着所有实例在原型上共享相同的功能。非常感谢您的详细解释。你的意思是说jquery对所有DOM对象都有包装器
O.O
@php\u nub\u qq我不知道jQuery到底有什么,但我知道它将HTML元素封装在自定义对象中。