What anti-patterns exist for JavaScript?
我发现不做的事情比学习应该做的更难学习。
根据我的经验,专家和中间人之间的区别在于能够从各种看似相同的方式中做出相同的选择。
那么,谈到JavaScript,你应该做什么样的事情以及为什么?
我能够为Java找到很多这些,但由于JavaScript的典型上下文(在浏览器中)与Java非常不同,我很想知道它会发生什么。
-
我看到的很少,整个语言都是反模式。我一直惊讶于Sun没有起诉"Java"品牌的污染。
-
@Paul:真的吗?什么被广泛认为是最好的脚本语言?这是动态的,可扩展的,具有一流的功能和我见过的最佳闭包实现。你在拖钓:/
-
不,我不是在拖钓。它对我来说看起来很乱,没有纪律。它被"认为是最好的脚本语言"的唯一原因是因为它是唯一可以在没有安装插件的情况下在每个浏览器上使用的脚本语言。
-
哦,而且我所见过的每个Javascript脚本都必须解决这样一个事实:IE的每个版本都以不同的方式实现它(并且没有一个能够正确实现)并不是我称之为好事的事实。
-
这只是非常不明智。自2001年左右以来,浏览器之间的差异实际上是微不足道的,而且非常抽象。
-
您在2001年作为抽象层使用了什么?
-
我写过一次JS方法,和其他每个理智的webdev一样。
-
我不会完全称每个人写自己的抽象层是微不足道的。 2001年正在推动它(YUI的开发始于2005年,jQuery于2006年发布)
-
我同意annakata这里 - javascript是我最喜欢的语言的一个重要竞争者,即使它有比其他任何主要语言更严重的问题(在规范和实现中)。
-
我和你在一起,Jimmy和annakata。语言背后的概念简直令人惊叹。
-
强烈建议你阅读"Javascript:The Good Parts",了解一些关于JavaScript"凌乱和无纪律"的观点 - 语言有瑕疵,但通常情况下,脚本开发人员"杂乱无序",他们会是喜欢用任何语言:)
-
浏览器API!= Javascript。 Paul对JS的负面评论似乎实际上是对浏览器API(即他们的DOM API)的抱怨。就这种情况而言,我同意。 Javascript确实因其API中的浏览器不一致而失望。
-
这个主题不应该是社区维基吗?
-
@annakata:答案是Python,对吗?虽然你遗漏了有关标准库的部分。
-
@Paul - 关于'Java'品牌名称的污染,你不是意识到大多数官方推荐称它为EMCA脚本,而不是Javascript。出于这个原因,Microsoft Visual Studio将其称为"JScript"。 'Javascript'实际上是非官方名称。很快被称为Oraclescript。
-
@Twisted,官方名称是Javascript,当它是新的。 ECMAScript试图让人们停止使用"Java"这个词是不成功的。
语言:
-
命名空间通过在全局上下文中创建大量变量来进行污染。
-
绑定事件处理程序的形式为'foo.onclick = myFunc'(不可扩展,应该使用attachEvent / addEventListener)。
-
几乎在任何非JSON上下文中使用eval
-
几乎每次使用document.write(使用像document.createElement这样的DOM方法)
-
针对Object对象的原型设计(BOOM!)
-
这是一个小的,但用'+'做大量的字符串连接(创建一个数组并加入它更有效)
-
参考不存在的undefined常数
设计/部署:
特定于Ajax:
编辑:我一直在想更多!
-
在AJAX的最后一点,X代表XML,如果你没有传递XML,你甚至没有做AJAX,你正在做AJAJSON,或者只是AJAJ。我不确定passwing JSON和传递XML之间的区别。
-
是的我知道X代表什么:)很多时候A也是假的。对于我们很多人很久以前所做的事情来说,这只是一个不幸的总称。仅供参考,JSON和XML之间的差异很大,但批判性的JSON更轻,并且采用原生格式JS不需要解析。
-
AJAX现在被用作一个总称,如DHTML。虽然严格来说你是对的。任何允许与服务器进行异步通信的东西都是我书中的AJAX。
-
@annakata:为什么不将这些作为单独的答案发布。这样,你获得更多积分,最好的单一答案浮动到顶部?
-
Kibee,我认为这只是一种纯粹的迂腐。这就是每个人都用术语AJAX的意思,所以我认为这是无关紧要的。忘记AJAX作为首字母缩略词,并将其视为我们所有人的意思。
-
@Allain:与将答案放在一个容易找到的地方相比,业力是无关紧要的 - 除了我的印象,这是SO的首选方法(确认任何人?)
-
我主要同意这一点 - 除了关于XML的最后一部分。我认为这是一种风味选择。我喜欢我的数据输出来自XML,因为它可以很容易地访问不同类型的应用程序。使用像jQuery这样的库也可以使遍历XML与访问JSON属性一样简单。
-
@andybaird - 为什么不能公开JSON和XML?我的应用程序通常在内部使用XML,在需要时使用XSLT到JSON。 jQuery让它变得简单,但JSON在那里表现更好。
-
@annakata - 我认为当两者都适用时,我不认为有必要同时做这两件事。可能表现更好,但它足够边缘,我宁愿节省开发时间。
-
@andybaird - 我们称之为个人选择,但是你可以从一次写入的JSON序列化器获得里程数,开发开销很小。
-
在"Ajax特定"下你指的是什么样的"民意调查"?例如,许多JS框架(如jQuery)都会自己轮询DOM或XMLHttpRequest对象。例如,jQuery有很多"setTimeout"调用,其中包含"不断检查文档是否已准备好"之类的注释。
-
你能解释一下你的第二点吗?除了只能附加一个事件,'foo.onclick = myFunc'有什么其他缺点?
-
@instantsetsuna - 这是主要的一个,但另一方面是你永远不知道当你再次直接绑定到一个事件时你隐含杀死了什么功能。使用attach更安全,因为你必须明确删除它。
-
@annakata:谢谢你的解释! :)
除了那些已经提到的......
-
使用for..in构造迭代数组
(迭代数组方法和索引)
-
使用Javascript内联,如
(不灵活并防止多个事件监听器)
-
使用'Function()'构造函数
(由于同样的原因eval()很糟糕)
-
将字符串而不是函数传递给setTimeout或setInterval
(内部也使用eval())
-
不使用分号依赖隐式语句
(养成习惯的坏习惯,可能导致意外行为)
-
使用/ * .. * /来阻止代码行
(可以干扰正则表达式文字,例如:/* /.*/ */)
<传授>
当然,不使用Prototype;)
传道>
-
有谁知道为什么我被打倒了?我是新人,不确定我是否违反了某种规则......
-
我不知道。我投了你的票。我喜欢你的大部分答案。
-
可能是因为你使用Prototype而不是jQuery ......似乎SO人群非常偏见jQuery?
-
@克里斯。那太荒谬了。我加了一个眼色!
-
并不意味着它不是这样;) - 如果你写了"原型",我会亲自投票给你:)
-
@annakata你的意思是我不应该大写?
-
<3原型。和原型。就此而言,还有原型设计。
对我来说最大的不是理解JavaScript编程语言本身。
-
过度使用对象层次结构并构建非常深的继承链。在大多数情况下,浅层次结构在JS中工作正常。
-
不了解基于原型的面向对象,而是构建大量的脚手架,使JS表现得像传统的OO语言。
-
当程序/函数式编程可以更简洁和有效时,不必要地使用OO范例。
然后是浏览器运行时的那些:
-
不使用事件委托或观察者模式(pub / sub)等良好建立的事件模式来优化事件处理。
-
当DOM节点可以在内存中并一次性附加时,进行频繁的DOM更新(如循环中的.appendChild)。 (巨大的性能优势)。
-
当可以使用本机方法时,过度使用库来选择具有复杂选择器的节点(getElementById,getElementByTagName等)。现在这个问题变得越来越少,但值得一提。
-
当您希望第三方脚本与您的页面位于同一页面时扩展DOM对象(最终会破坏彼此的代码)。
最后是部署问题。
-
不缩小文件。
-
Web服务器配置 - 不是压缩文件,不是明智地缓存它们。
我有一些客户端优化技巧,涵盖了我上面提到的一些事情,以及更多,在我的博客上。 plug>
-
浏览器检测(而不是测试您要使用的特定方法/字段是否存在)
-
在大多数情况下使用alert()
另请参阅Crockford的"Javascript:The Good Parts",以避免各种其他事情。 (编辑:警告,他对他的一些建议有点严格,比如使用"==="而不是"=="所以带上任何粒子的盐为你工作)
-
是的警报很丑啊:)
-
我也对Crockford所说的一些事情提出异议(例如他的立场和继续)
-
浏览器检测的例外情况是浏览器报告它支持方法或属性,但您知道实现是错误的/有缺陷的。 IE支持elem.setAttribute(name,value),但肯定不支持它。
-
@annakata:好的一点,我也是
一些事情就在我的头顶。当我想到更多时,我会编辑这个列表。
-
不要污染全局命名空间。而是组织对象中的东西;
-
不要省略变量的'var'。这会污染全局命名空间,并可能使您遇到其他此类脚本的麻烦。
-
请注意,jslint(jslint.com)将针对这两者发出警告,因此在您忘记'var'并且意外创建全局变量的情况下它会很有用。
-
请注意,Javascript没有类。但我认为你的意思是功能范围或对象属性/方法。
-
@thomasrutter - 请原谅,纠正。 :)
-
哇我的两条评论差不多正好5年......
-
@thomasrutter - 让你感觉老了,不是吗? XD
任何使用'与'
with (document.forms["mainForm"].elements) {
input1.value ="junk";
input2.value ="junk";
}
BLOCKQUOTE>
-
我想知道当我们为Javascript获得更好的代码分析工具时,这是否会成为一个问题
-
请参见:stackoverflow.com/questions/61552/…讨论"与";恕我直言,至少有一个有效的用途,可能更多......但作为范围控制的手段,不是修改对象成员的便利。
任何提及
在你的代码中,除非它在特殊代码中,只是为了IE来克服IE错误。 (咳嗽document.getElementById()咳嗽)
创建语句时使用大括号定位很糟糕
由于自动分号插入,您应该始终在语句后放置一个大括号。
例如:
1 2 3 4 5 6 7
| function()
{
return
{
price: 10
}
} |
与此有很大不同:
1 2 3 4 5
| function(){
return{
price: 10
}
} |
因为在第一个例子中,javascript会为你实际插入一个分号:
1 2 3 4 5 6 7
| function()
{
return; // oh dear!
{
price: 10
}
} |
将setInterval用于可能长时间运行的任务。
在需要重复执行某些操作的情况下,应该使用setTimeout而不是setInterval。
如果你使用setInterval,但计时器中执行的函数在计时器下一次计时时没有完成,这很糟糕。而是使用setTimeout使用以下模式
1 2 3 4 5 6 7 8
| function doThisManyTimes(){
alert("It's happening again!");
}
(function repeat(){
doThisManyTimes();
setTimeout(repeat, 500);
})(); |
Paul Irish对我从jQuery源视频中学到的10件事情进行了很好的解释
-
"If you use setInterval, but the function that is executed in the timer is not finished by the time the timer next ticks, this is bad."为什么这么糟糕?怎么了?
-
@Kirk这取决于函数的作用,如果函数改变了视图,然后启动一个ajax请求,谁的回调对视图做了某些事情,那么这个序列看起来不同步是非常不可取的。例如股票数据。
-
Javascript是事件驱动的,一个执行上下文中的所有内容都按照排队的顺序在一个线程中发生。将setInterval与一个需要很长时间的函数一起使用没有任何负面后果 - 这绝对没问题。什么都不会"中断"其他代码。它只是意味着对该函数的下一次调用将被延迟,直到当前调用结束。
-
在您启动ajax请求的函数示例中 - 如果它是同步请求,则函数的其余部分将等待直到请求完成,然后函数的其余部分将运行,然后后续setinterval ticks中的任何排队函数将在执行之后执行那。如果它是一个异步的AJAX调用,那么你将不得不处理回调可能以不可预测的顺序相对于其他回调的可能性,其中setinterval vs settimeout不会改变。
不使用基于社区的框架来执行DOM操作,事件处理等重复性任务。
-
我个人的选择是jQuery,但实际的框架很少。只要它不是本土的。
-
我有点不同意这一点 - 有时一个特殊的解决方案比一般解决方案更好,我有很多我自己的JS,我相信它优于jQueries等价物。可能我应该把这些东西给jQuery,但重点是群众并不总是正确的。
-
那么我们同意不同意。 :)即使你的个人框架是一个更好的匹配,你必须做的测试,你可以通过使用基于社区的方法获得"免费"。
-
好吧,不是真的,我已经拖了这大块代码5年了:)
-
拖动是一个恰当的比喻。 :)
-
当你想要使用一小部分东西时,我觉得大框架有点笨重。可能YUI在这方面有正确的想法,你可以只加载你需要的模块,尽管它的功能非常冗长。但是如果你把jQuery缩小到大小,你会遇到像维护自己的jQuery fork一样的情况。我不知道答案是什么
很少有效的缓存:
-
当您可以使用Google的Libraries API等共享API加速页面加载时,请不要在您的服务器上存储库的副本(jQuery,Prototype,Dojo)
-
将您可以合并的所有脚本合并并缩小为一个
-
使用mod_expires为您的所有脚本提供无限的缓存生命周期(永不重新下载)
-
版本化您的javascript文件名,以便客户端可以进行新的更新,而无需重新加载/重新启动
(即myFile_r231.js,或myFile.js?r = 231)