先看幾個(gè)例子:
age 變量在函數(shù)定義之前定義的例子
age = 99
r = -> age = 0
r()
console.log “i am #{age} years old”
#puts “i am 99 years old”
age 變量在函數(shù)定義之后定義的例子
r = -> age = 0
age = 99
r()
console.log “i am #{age} years old”
#also puts “i am 99 years old”
age 變量在函數(shù)外無定義的例子
r = -> age = 0
r()
console.log “i am #{age} years old”
#ReferenceError: age is not defined
很顯然 CoffeeScript 中的變量作用域與 Javascript 中是一樣的。其中有三條規(guī)則:
每個(gè)函數(shù)都是一個(gè)獨(dú)立作用域,創(chuàng)建一個(gè)函數(shù)是創(chuàng)建作用域的唯一方法;(可參考 javascript 核心函數(shù)的說明)
變量的作用域僅在其被定義的范圍內(nèi)有效;
在變量的作用域以外,其是不可見的。
那為什么函數(shù)中直接用 age 做變量并賦值卻沒有改變?nèi)肿兞?age (r函數(shù)之外的那個(gè)變量)的值呢?
因?yàn)?coffee 程序解析成 js 程序時(shí),r 函數(shù)內(nèi)通過 var 關(guān)鍵字重新定義了 age,使得 age 成為 r 函數(shù)內(nèi)的一個(gè)變量,此變量的作用域僅為 r 函數(shù)內(nèi)部,而不影響外部的 age 變量,以上第一個(gè)例子解析成 js 就是:
var r, age;
age = 99;
r = function() {
var age;
return age = 0;
};
r();
console.log(“i am ” + age + ” years old”);
如果將例子中 r 函數(shù)中的語句改為:
age = 99
r = -> age++
r()
console.log “i am #{age} years old”
#puts “i am 100 years old”
或者其他非賦值語句,此時(shí)的 age 則為全局中的 age 變量。
CoffeeScript編譯器會(huì)考慮所有變量,保證每個(gè)變量都在詞法域里適當(dāng)?shù)乇欢x,你永遠(yuǎn)不需要自己去寫 var。那么在不同的上下文環(huán)境下出現(xiàn)了同名變量,CoffeeScript是怎么處理的呢,看個(gè)例子:
#編譯前
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,變量的定義都被推到相關(guān)的頂層作用域了。在fn函數(shù)內(nèi)部只聲明了inner,沒有聲明outer。實(shí)際上CoffeeScript變量定義是跟作用域和聲明順序有關(guān)的,看CoffeeScript代碼fn的代碼塊,因?yàn)樵趂n里outer定義之前,函數(shù)外已經(jīng)定義了outer,所以outer不在重新聲明。 那為啥外面也聲明了inner,fn內(nèi)部又重新定義了inner,因?yàn)轫樞虻脑?,函?shù)fn內(nèi)部的聲明在前,所以編譯后的代碼重新定義了inner。函數(shù)外部是拿不到函數(shù)內(nèi)的變量的,所以外部的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;
};
函數(shù)內(nèi)部先聲明:
#編譯前
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;
更多建議: