向对象添加方法

时间:2013-09-18 16:08:32

标签: javascript function object methods

在JS编写了一段时间后,我决定制作自己的框架。类似于jQuery的东西。但是一个非常简单的版本。经过一些谷歌搜索,我把这段代码放在一起:

function $elect(id) {
    if (window === this) {
        return new $elect(id);
    }
    this.elm = document.getElementById(id);
}

$elect.prototype = {
    hide:   function () { this.elm.style.display = 'none';  },
    show:   function () { this.elm.style.display = '';      },
    toggle: function ()
            {
                if (this.elm.style.display !== 'none') {
                    this.elm.style.display = 'none';
                } else {
                    this.elm.style.display = '';
                }
            }
};

到目前为止,这似乎有效。但我对功能不感兴趣。我想了解逻辑。添加方法部分是可以理解的。虽然我不明白

的功能
    if (window === this) {
        return new $elect(id);
    }

如果我删除它,功能中断。由于这是一个if语句,因此有2个结果。 Truefalse。所以我尝试删除if语句,只使用return new $elect(id);假设window === this返回true,但这不起作用。然后我认为它可能会返回false,因此删除了整个if语句。这也行不通。有人可以开导我吗?这段代码也有效吗?我可能错过了一些东西。

刚刚在jsfiddle上测试过,它不起作用。虽然它适用于jsbin o.O

jsfiddle jsbin

编辑:使用$elect(id).toggle();来调用它。虽然你可以查看演示。

6 个答案:

答案 0 :(得分:1)

  

我想了解逻辑。

$electconstructor function,应该使用new keywordnew $select)进行调用。如果不是($elect()),那么会发生什么?没有构造实例,this keyword将指向全局对象(window) - 我们不想要它。因此,当它检测到它使用new正确调用自身并返回时,此片段就是防范该场合。

  

如果我删除它,功能中断

当你在没有守卫的情况下调用它$elect(id)时,它会向全局对象添加elm属性(本质上是一个全局变量)并且不返回任何内容。尝试在其上调用.toggle()方法将产生异常undefined has no method 'toggle'

  

我试图删除if语句,假设window === this返回true

那么,你刚刚创建了一个无限递归函数,在调用时会导致堆栈溢出异常。


顺便说一句,proper way to guard against new-less invocation不与window进行比较(全局对象在非浏览器环境中可能有不同的名称)并假设其他一切都没问题,但要检查是否正确遗产。您希望构造函数仅应用于“类”的实例,即从$elect.prototype继承的对象。例如,使用new调用时可以保证这一点。要进行此检查,您将使用instanceof operator

function $elect(id) {
    if (! (this instanceof $elect)) {
        return new $elect(id);
    }
    this.elm = document.getElementById(id);
}

这也使得警卫的意图明确。

答案 1 :(得分:1)

要了解该条件的工作原理,您必须首先知道全局范围this引用window对象。在本地范围内,例如在对象内,this引用对象本身。

您的$elect函数是框架的构造函数。如果你直接调用它,就像这样:

$elect('some-id-blah')

它将首先意识到您正在尝试创建一个实例(因为条件window === this将评估为true),并且它将递归地创建自己的新实例。一旦这样做,this将不再引用window对象,它将引用库的新实例,因此不会满足条件。

我希望这有点可以理解。

答案 2 :(得分:0)

这个逻辑:

if (window === this) {
    return new $elect(id);
}

确保将构造函数作为函数调用:

var foo = $elect(id);

而不是构造函数:

var fo = new $elect(id);

它将返回正确的结果 - 一个新的$ elect对象。当作为函数调用时,默认上下文将是全局上下文或window在浏览器中运行时,触发if子句并返回将其作为构造函数调用的结果。


为什么它不适合你的小提琴

在链接小提琴中,设置将代码包装在onload处理程序中。结果如下:

window.onload=function(){
function $elect(id) {
    if (window === this) {
        return new $elect(id);
    }
    this.elm = document.getElementById(id);
}

$elect.prototype = {
    hide:   function () { this.elm.style.display = 'none';  },
    show:   function () { this.elm.style.display = '';      },
    toggle: function ()
            {
                if (this.elm.style.display !== 'none') {
                    this.elm.style.display = 'none';
                } else {
                    this.elm.style.display = '';
                }
            }
};
}

因此,您的$elect变量在onload处理程序范围之外不可见。

通常,您希望将一个变量添加到全局范围以启用对框架的访问。在上面的代码末尾添加的类似内容将使其可见:

 window.$elect = $elect;

Demo Fiddle

答案 3 :(得分:0)

首先要明白的是,这个函数正在调用自己:

function $elect(id) {
    if (window === this) {
        return new $elect(id);
    }
    this.elm = document.getElementById(id);
}

第一次调用函数窗口将是===这个。因为你正在调用函数作为方法。当作为方法调用时,函数将绑定到函数/方法所属的对象。在此示例中,this将绑定到窗口,即全局范围。

然后使用new关键字,您将该函数作为构造函数调用。当作为构造函数调用时,将创建一个新对象,this将绑定到该对象,因此this第二次不再引用window

使用$ elect的新实例,您还可以正确地将一个局部变量elm设置为该实例,允许您的其他函数稍后调用该elm。

答案 4 :(得分:0)

您的函数是构造函数。默认情况下,作为方法在任何其他对象上未显式调用(this,而不是$elect())的任何函数中的foo.$elect()将传递给全局对象(window)在this。但是if检查如果this确实引用window对象,则执行return new $elect(id);new $elect(id)执行以下操作:

  • 制作$elect.prototype
  • 的新实例
  • 将新创建的实例放入this并再次调用该方法。

在第二次传递中,this === window评估为false

答案 5 :(得分:0)

如果你这样称呼它:

$elect("theId").hide();

第一次将其作为一个函数调用并找到window === this并执行此操作:

return new $elect("theId")

创建一个新的并再次调用该函数。 (无论函数返回的第二次调用将返回。)

第二次,它被称为构造函数,所以window !== this它将向下传递以找到元素并将其存储在内部。

不从函数本身返回任何内容的构造函数调用将返回创建的实例。

这样.hide()部分将以this的正确值(第一次创建的实例)执行。元素将从屏幕上消失。

请注意,如果您这样称呼它:

var bob = {};
bob.$select("theId").hide();

它不起作用,因为this设置为bob得到和'elm'属性设置,并且没有'hide'属性被调用,因为它不是$elect一种对象。

注意

如果其他函数中的所有其他方法都返回this,您将能够将它们链接起来:

$elect('theId').show().red();

假设您添加了一个将元素着色为红色的函数。