我想切换到 Coffeescript 有一段时间了,昨天我以为我终于卖掉了,但后来我偶然发现了 Armin Ronachers article关于 Coffeescript 中的阴影。
Coffeescript 现在确实放弃了阴影,如果您对嵌套循环使用相同的迭代器就是该问题的一个示例。
var arr, hab, i;
arr = [[1, 2], [1, 2, 3], [1, 2, 3]];
for(var i = 0; i < arr.length; i++){
var subArr = arr[i];
(function(){
for(var i = 0; i < subArr.length; i++){
console.log(subArr[i]);
}
})();
}
因为 cs 只声明一次变量,我无法在 coffeescript 中执行此操作
阴影已被有意删除,我想了解为什么 cs 作者想要摆脱这样的功能?
更新:这是一个better example为什么阴影很重要,源自关于此问题的问题 on github
PS:我不是在寻找告诉我可以插入带有反引号的普通 Javascript 的答案。
最佳答案
如果您阅读关于 this ticket 的讨论,您可以看到 CoffeeScript 的创建者 Jeremy Ashkenas 解释了禁止显式阴影之间的一些推理:
We all know that dynamic scope is bad, compared to lexical scope, because it makes it difficult to reason about the value of your variables. With dynamic scope, you can't determine the value of a variable by reading the surrounding source code, because the value depends entirely on the environment at the time the function is called. If variable shadowing is allowed and encouraged, you can't determine the value of a variable without tracking backwards in the source to the closest var variable, because the exact same identifier for a local variable can have completely different values in adjacent scopes. In all cases, when you want to shadow a variable, you can accomplish the same thing by simply choosing a more appropriate name. It's much easier to reason about your code if a local variable name has a single value within the entire lexical scope, and shadowing is forbidden.
So it's a very deliberate choice for CoffeeScript to kill two birds with one stone -- simplifying the language by removing the "var" concept, and forbidding shadowed variables as the natural consequence.
如果您在 CoffeeScript 问题中搜索“scope”或“shadowing”,您会发现它一直出现。我不会在这里发表意见,但要点是 CoffeeScript Creators 相信它会导致更简单的代码,更不容易出错。
好吧,我会发表一点意见:阴影并不重要。你可以想出人为的例子来说明为什么这两种方法都更好。事实是,无论是否有阴影,您都需要“向上”搜索作用域链以了解变量的生命周期。如果您显式声明您的变量 ala JavaScript,您可能能够更快地短路。不过没关系。如果您不确定给定函数的范围内有哪些变量,那您就错了。
阴影是在CoffeeScript 中是可能的,而不包括JavaScript。如果您实际上需要一个您知道是局部作用域的变量,您可以获取它:
x = 15
do (x = 10) ->
console.log x
console.log x
因此,如果这种情况在实践中出现的可能性很小,则有一个相当简单的解决方法。
就个人而言,我更喜欢显式声明每个变量的方法,并将提供以下内容作为我的“论据”:
doSomething = ->
...
someCallback = ->
...
whatever = ->
...
x = 10
...
这很好用。然后突然一个实习生出现并添加了这行:
x = 20
doSomething = ->
...
someCallback = ->
...
whatever = ->
...
x = 10
...
然后,砰,代码被破坏了,但破坏直到很晚才出现。哎呀!使用 var,就不会发生这种情况。但是对于“通常是隐式范围,除非您另有说明”,它会有。所以。无论如何。
我在一家在客户端和服务器上使用 CoffeeScript 的公司工作,我从未听说过这种情况在实践中发生过。我认为不必在任何地方键入单词 var 所节省的时间比因范围界定错误(永远不会出现)而损失的时间要多。
自从写下这个答案后,我已经在实际代码中看到这个错误发生了两次。每次发生,都非常烦人且难以调试。我的感觉已经改变,认为 CoffeeScript 的选择是一个糟糕的时代。
一些类似 CoffeeScript 的 JS 替代品,例如 LiveScript 和 coco,为此使用两种不同的赋值运算符:= 声明变量和 := 修改外部变量范围。这似乎是一个比仅保留 var 关键字更复杂的解决方案,而且一旦 let 被广泛使用,这种解决方案也不会很好。
关于javascript - 为什么 Coffeescript 认为阴影是个坏主意,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15223430/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?