草庐IT

JavaScript 函数别名似乎不起作用

coder 2023-07-03 原文

我只是在阅读this question并想尝试使用别名方法而不是函数包装方法,但我似乎无法让它在 Firefox 3 或 3.5beta4 或 Google Chrome 中工作,无论是在调试窗口还是在测试网页中。

Firebug :

>>> window.myAlias = document.getElementById
function()
>>> myAlias('item1')
>>> window.myAlias('item1')
>>> document.getElementById('item1')
<div id="item1">

如果我把它放在一个网页中,对 myAlias 的调用会给我这个错误:
uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: file:///[...snip...]/test.html :: <TOP_LEVEL> :: line 7" data: no]

Chrome(为了清楚起见插入了>>>):
>>> window.myAlias = document.getElementById
function getElementById() { [native code] }
>>> window.myAlias('item1')
TypeError: Illegal invocation
>>> document.getElementById('item1')
<div id=?"item1">?

在测试页面中,我得到相同的“非法调用”。

难道我做错了什么?其他人可以重现这个吗?

另外,奇怪的是,我刚刚尝试过,它在 IE8 中工作。

最佳答案

我深入研究以了解这种特殊行为,并且我认为我找到了一个很好的解释。

在我解释为什么你不能使用别名 document.getElementById 之前,我将尝试解释 JavaScript 函数/对象是如何工作的。

每当您调用 JavaScript 函数时,JavaScript 解释器都会确定一个范围并将其传递给该函数。

考虑以下功能:

function sum(a, b)
{
    return a + b;
}

sum(10, 20); // returns 30;

此函数在 Window 范围内声明,当您调用它时,this 的值sum 函数内部将是全局 Window目的。

对于 'sum' 函数,'this' 的值是什么并不重要,因为它没有使用它。

考虑以下功能:
function Person(birthDate)
{
    this.birthDate = birthDate;    
    this.getAge = function() { return new Date().getFullYear() - this.birthDate.getFullYear(); };
}

var dave = new Person(new Date(1909, 1, 1)); 
dave.getAge(); //returns 100.

当您调用 dave.getAge 函数时,JavaScript 解释器会看到您正在调用 dave 上的 getAge 函数。对象,所以它设置 thisdave并调用getAge功能。 getAge()将正确返回 100 .

你可能知道在 JavaScript 中你可以使用 apply 来指定作用域。方法。让我们试试看。
var dave = new Person(new Date(1909, 1, 1)); //Age 100 in 2009
var bob = new Person(new Date(1809, 1, 1)); //Age 200 in 2009

dave.getAge.apply(bob); //returns 200.

在上面的行中,不是让 JavaScript 决定范围,而是手动将范围作为 bob 传递。目的。 getAge现在将返回 200即使你“认为”你调用 getAgedave目的。

以上所有内容有什么意义?函数“松散地”附加到您的 JavaScript 对象上。例如。你可以做
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));

bob.getAge = function() { return -1; };

bob.getAge(); //returns -1
dave.getAge(); //returns 100

让我们进行下一步。
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;

dave.getAge(); //returns 100;
ageMethod(); //returns ?????
ageMethod执行抛出错误!发生了什么?

如果您仔细阅读我的上述几点,您会注意到 dave.getAge使用 dave 调用方法如this对象,而 JavaScript 无法确定 ageMethod 的“范围”执行。所以它通过全局'Window'作为'this'。现在为 window没有 birthDate属性(property), ageMethod执行将失败。

如何解决这个问题?简单的,
ageMethod.apply(dave); //returns 100.

以上所有内容都有意义吗?如果是这样,那么您将能够解释为什么您无法使用别名 document.getElementById :
var $ = document.getElementById;

$('someElement'); 
$window 调用如this如果 getElementById预计实现 this成为 document ,它会失败。

再次解决这个问题,你可以做
$.apply(document, ['someElement']);

那么为什么它可以在 Internet Explorer 中运行呢?

不知道getElementById的内部实现在 IE 中,但 jQuery 源代码(inArray 方法实现)中的注释说在 IE 中,window == document .如果是这种情况,则使用别名 document.getElementById应该在IE中工作。

为了进一步说明这一点,我创建了一个详细的示例。看看Person下面的功能。
function Person(birthDate)
{
    var self = this;

    this.birthDate = birthDate;

    this.getAge = function()
    {
        //Let's make sure that getAge method was invoked 
        //with an object which was constructed from our Person function.
        if(this.constructor == Person)
            return new Date().getFullYear() - this.birthDate.getFullYear();
        else
            return -1;
    };

    //Smarter version of getAge function, it will always refer to the object
    //it was created with.
    this.getAgeSmarter = function()
    {
        return self.getAge();
    };

    //Smartest version of getAge function.
    //It will try to use the most appropriate scope.
    this.getAgeSmartest = function()
    {
        var scope = this.constructor == Person ? this : self;
        return scope.getAge();
    };

}

对于Person上面的函数,这里是各种getAge方法会表现出来。

让我们使用 Person 创建两个对象功能。
var yogi = new Person(new Date(1909, 1,1)); //Age is 100
var anotherYogi = new Person(new Date(1809, 1, 1)); //Age is 200
console.log(yogi.getAge()); //Output: 100.

直截了当,getAge 方法得到 yogi对象为 this和输出 100 .
var ageAlias = yogi.getAge;
console.log(ageAlias()); //Output: -1

JavaScript 解释器集 window对象为 this和我们的getAge方法将返回 -1 .
console.log(ageAlias.apply(yogi)); //Output: 100

如果我们设置正确的范围,你可以使用 ageAlias方法。
console.log(ageAlias.apply(anotherYogi)); //Output: 200

如果我们传入一些其他人对象,它仍然会正确计算年龄。
var ageSmarterAlias = yogi.getAgeSmarter;    
console.log(ageSmarterAlias()); //Output: 100
ageSmarter函数捕获原始this对象,所以现在您不必担心提供正确的范围。
console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!
ageSmarter 的问题是您永远不能将范围设置为其他对象。
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias()); //Output: 100
console.log(ageSmartestAlias.apply(document)); //Output: 100
ageSmartest如果提供了无效范围,函数将使用原始范围。
console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200

您仍然可以通过另一个 Person反对getAgeSmartest . :)

关于JavaScript 函数别名似乎不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1007340/

有关JavaScript 函数别名似乎不起作用的更多相关文章

  1. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  2. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  3. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  4. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  5. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  6. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  7. ruby-on-rails - 在 heroku 的 .fonts 文件夹中包含自定义字体,似乎无法识别它们 - 2

    Heroku支持人员告诉我,为了在我的Web应用程序中使用自定义字体(未安装在系统中,您可以在bash控制台中使用fc-list查看已安装的字体)我必须部署一个包含所有字体的.fonts文件夹里面的字体。问题是我不知道该怎么做。我的意思是,我不知道文件名是否必须遵循heroku的任何特殊模式,或者我必须在我的代码中做一些事情来考虑这种字体,或者如果我将它包含在文件夹中它是自动的......事实是,我尝试以不同的方式更改字体的文件名,但根本没有使用该字体。为了提供更多详细信息,我们使用字体的过程是将PDF转换为图像,更具体地说,使用rghostgem。并且最终图像根本不使用自定义字体。在

  8. ruby-on-rails - 将字符串转换为 ruby​​-on-rails 中的函数 - 2

    我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。

  9. ruby-on-rails - "assigns"在 Ruby on Rails 中有什么作用? - 2

    我目前正在尝试学习RubyonRails和测试框架RSpec。assigns在此RSpec测试中做什么?describe"GETindex"doit"assignsallmymodelas@mymodel"domymodel=Factory(:mymodel)get:indexassigns(:mymodels).shouldeq([mymodel])endend 最佳答案 assigns只是检查您在Controller中设置的实例变量的值。这里检查@mymodels。 关于ruby-o

  10. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

随机推荐