为什么我的JavaScript在JSFiddle中不能正常工作?

116
我无法确定这个 JSFiddle 的问题所在。

HTML:

<input type="button" value="test" onclick="test()">

JavaScript:

function test(){alert("test");}

当我点击按钮时,没有任何反应。控制台显示“未定义test”。

我已经阅读了JSFiddle的文档 - 文档中说JS代码添加到<head>,HTML代码添加到<body>(因此该JS代码在html之前,并应该可以使用)。


去掉括号也可以在正常的非混淆情况下工作,但尽可能将JavaScript与HTML分离是明智的建议。我只允许自己使用style =" display:none"这种违反CSS行内样式规范的写法。 - Adrian Bartholomew
如果您正在寻找相反的问题,即代码在JSFiddle中可以运行但在本地无法运行,请参见在对象内使用document.getElementById()在JSFiddle中可行,在实际中会出现TypeError。为什么?。两种行为有相同的原因:JSFiddle自动将JS代码包装在一个函数中,该函数在DOM准备就绪时立即执行,这也导致onclick超出范围。 - Sebastian Simon
7个回答

101
如果未指定包装设置,则默认为"onLoad"。这将导致所有JavaScript都被包装在在结果加载后运行的函数中。所有变量都是局部变量,因此无法在全局范围内使用。
将包装设置更改为"no wrap"即可解决问题:

http://jsfiddle.net/zalun/Yazpj/1/

我将框架切换为“无库”,因为您没有使用任何库。


60

该函数在加载处理程序内部被定义,因此处于不同的作用域。如评论中@ellisbben所指出,您可以通过在window对象上明确定义它来修复此问题。更好的做法是将处理程序应用于对象而不引人注目:http://jsfiddle.net/pUeue/

$('input[type=button]').click( function() {
   alert("test");   
});

请注意,使用此方式应用处理程序可以保持HTML的干净整洁。我正在使用jQuery,但您可以使用框架或不使用框架,或者使用其他框架。


@Innuendo - jsFiddle使用单独的框架来处理代码/HTML/样式表。您需要在函数调用中引用该框架,但由于该框架没有名称,因此没有真正简单的方法来实现这一点。这实际上是jsfiddle工作方式的问题,但将JavaScript完全分离仍然是一个好主意。 - tvanfosson
5
@tvanfosson 你的解决方案可行,但是jsfiddle没有使用单独的框架来显示结果;请参见http://jsfiddle.net/Yazpj/show/。最初它没有起作用的原因是 test 被定义在 onLoad 函数内部;使用 window.test = function(){/*...*/} 可以使其正常工作。 - ellisbben
@ellisbben - 如果我使用Firebug来检查DOM,那么每个独立的窗格都存在于一个单独的iframe中。 - tvanfosson
1
是的,但如果您检查用于显示示例的单个iframe,则会发现它将所有代码放在一个不使用框架的单个页面中,因此这些框架无法破坏您的示例。将“show”附加到任何jsfiddle URL上即可查看我所说的内容:jsfiddle.net/Yazpj/show - ellisbben

22

还有一种方法,将你的函数声明为一个变量,像这样:

test = function() {
  alert("test");
}

jsFiddle


细节

根据 @nnnnnn 的评论编辑:

@nnnnnn :

不使用 var,为什么会解决这个问题?

当你像这样定义一个函数时:

var test = function(){};

该函数在本地定义,但是如果您在没有使用var的情况下定义您的函数:

test = function(){};

test 在顶层作用域的 window 对象上定义。

为什么这能起作用?

像 @zalun 所说:

如果您不指定包装设置,它将默认为 "onLoad"。这会导致所有 JavaScript 都被包裹在一个在结果加载后运行的函数中。所有变量都是此函数的局部变量,因此无法在全局范围内使用。

但如果您使用此语法:

test = function(){};

你可以访问函数test,因为它在全局范围内定义。


参考:


2
如果你只是在JSFiddle中测试一小段代码,那么这确实是最简单的方法。 - DOK
但是,为什么这样做有效呢?您提供的“更多信息”链接并没有解释问题与作用域有关,也没有解释为什么不使用“var”来说出test = 会修复它。 - nnnnnn
@R3tep 嗯,你的第一个链接是:http://jsfiddle.net/R3tep/Yazpj/1406/ ,但是对我来说alert没有任何反应。我用的是Chrome浏览器。 - Ced
@R3tep 是的,它可以使用console.log。我会在SO上发布一个问题,因为我相信我没有警报框与我在iframes中遇到的另一个问题有关。 - Ced
@R3tep 顺便说一下,我找到了为什么它不起作用的原因。你的 Chrome 没有更新,所以当你更新时,你也可能会遇到这个问题。我在沙盒中添加了 allow-modals,它让它工作了。如果你碰巧遇到和我一样的问题,请记住这个解决方法。干杯! - Ced
1
@R3tep,我想你可能误解了我的意思,但我也不确定。你的代码是/曾经很好。JSFiddle的编码存在问题(在用于显示结果的iframe的沙盒属性中缺少值)。这使得它在某些版本的Chrome上无法使用。我在他们的GitHub上发送了一个问题报告。我对此很感兴趣,因为我以为在我的网站上遇到的问题与此相同,但实际上不是。谢谢。 - Ced

3
在“框架和扩展”面板中更改包装设置,选择“不在<body>内包装”。

-1
<script> 
function test(){
 alert("test");   
}
</script>

<input type="button" value="test" onclick="test()">

-1

你的代码没有问题。只需从右侧选择扩展名为onLoad()。


-3
Select OnDomready

HTML:

<input id="dButton" type="button" value="test"/>

JavaScript:

addEventListener('load', init, false);

function init()
{
  oInput = document.getElementById('dButton');
  oInput.onclick = test;
}

function test(){
  alert("test");
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接