CoffeeScript作用域
先看几个例子:
age 变量在函数定义之前定义的例子
age = 99
r = -> age = 0
r()
console.log “i am #{age} years old”
#puts “i am 99 years old”
age 变量在函数定义之后定义的例子
r = -> age = 0
age = 99
r()
console.log “i am #{age} years old”
#also puts “i am 99 years old”
age 变量在函数外无定义的例子
r = -> age = 0
r()
console.log “i am #{age} years old”
#ReferenceError: age is not defined
很显然 CoffeeScript 中的变量作用域与 Javascript 中是一样的。其中有三条规则:
每个函数都是一个独立作用域,创建一个函数是创建作用域的唯一方法;(可参考 javascript 核心函数的说明)
变量的作用域仅在其被定义的范围内有效;
在变量的作用域以外,其是不可见的。
那为什么函数中直接用 age 做变量并赋值却没有改变全局变量 age (r函数之外的那个变量)的值呢?
因为 coffee 程序解析成 js 程序时,r 函数内通过 var 关键字重新定义了 age,使得 age 成为 r 函数内的一个变量,此变量的作用域仅为 r 函数内部,而不影响外部的 age 变量,以上第一个例子解析成 js 就是:
var r, age;
age = 99;
r = function() {
var age;
return age = 0;
};
r();
console.log(“i am ” + age + ” years old”);
如果将例子中 r 函数中的语句改为:
age = 99
r = -> age++
r()
console.log “i am #{age} years old”
#puts “i am 100 years old”
或者其他非赋值语句,此时的 age 则为全局中的 age 变量。
CoffeeScript编译器会考虑所有变量,保证每个变量都在词法域里适当地被定义,你永远不需要自己去写 var。那么在不同的上下文环境下出现了同名变量,CoffeeScript是怎么处理的呢,看个例子:
#编译前
outer = 1
fn = ->
inner = -1
outer = 10
return null
inner = 4
//编译后
var fn, inner, outer;
outer = 1;
fn = function() {
var inner;
inner = -1;
outer = 10;
return null;
};
inner = 4;
在最外层的作用域下声明了outer、inner、fn,变量的定义都被推到相关的顶层作用域了。在fn函数内部只声明了inner,没有声明outer。实际上CoffeeScript变量定义是跟作用域和声明顺序有关的,看CoffeeScript代码fn的代码块,因为在fn里outer定义之前,函数外已经定义了outer,所以outer不在重新声明。 那为啥外面也声明了inner,fn内部又重新定义了inner,因为顺序的原因,函数fn内部的声明在前,所以编译后的代码重新定义了inner。函数外部是拿不到函数内的变量的,所以外部的inner在外围的作用域下也声明了inner。大家看下下面的代码,有助于理解:
外部先声明:
#编译前
outer = 1
inner = 4
fn = ->
inner = -1
outer = 10
return null
//编译后
var fn, inner, outer;
outer = 1;
inner = 4;
fn = function() {
inner = -1;
outer = 10;
return null;
};
函数内部先声明:
#编译前
fn = ->
inner = -1
outer = 10
return null
outer = 1
inner = 4
//编译后
var fn, inner, outer;
fn = function() {
var inner, outer;
inner = -1;
outer = 10;
return null;
};
outer = 1;
inner = 4;
更多建议: