close

  Javascript的函式與變數在其可視性(或活動範圍[Scope])上與其他一般語言(主要是C語言)比較起來有相當大的不一樣,主要有以下兩樣差別:

  1. 變數可視性方面,一般語言的變數可視性是屬於區塊相依的,也就是變數只在把它包覆起來的”{} 程式區塊"可視(In Scope),出了區塊就不可視(Out Scope);但Javascript變數可視性是屬於函式相依的,也就是"變數從其在函式內被宣告處開始直到函式結束都是可視的(In Scope)
  2. 函式可視性方面,一般語言是只有在函式宣告後方有函式可視性,也就是在函式宣告之前不能使用函式,因為函式不存在;在Javascript的函式則有一個特別的特性"提吊(Hoisting)",一個內部具名函式(具名子函式)可視性包括其外部函式(父函式)的全部範圍,也就是說在某一函式內你是可以在定義其具名子函式之前就叫用該子函式。

口說無憑,讓我們舉幾個Javascript的例子:

  下例Sample 1中,sub function內的b在宣告前=undefined,因為它還沒被宣告,所以仍然不可視。但在sub function內的b=10,因為b已經被宣告了,且因為a<100,所以b=a=10,所以b在函式內從宣告處開始可視。最後在sub function外嘗試列印b時得到一個未定義的錯誤,這是因為b的可視性從函式內宣告處開始,到函式定義結束就已經結束了,所以在sub function外的世界裡b等同於不曾存在過,也可以說是完全的out scope

 

Sample 1.

function sub() {

    console.log("sub functionb在宣告處之前應該等於多少?")

    console.log(b)

 

    var a = 10

    var b = 1

    if(a<100) { b=a}

    console.log("sub functionb應該等於多少?")

    console.log(b)

  }

  try {

    sub()

    console.log("sub functionb應該等於多少?")

    console.log(b)

  } catch (e) {

      console.log("Error: " + e.message)

  }

 

執行結果:

  接著在Sample 2 中,可以看到函式的可視性行為,首先定義一個函式outter(),在其內部宣告並定義子函式inner()之前,我們便嘗試呼叫inner(7),由於提吊的特性,內部函式的可視性及於它的外部函式所有範圍,所以在外部呼叫outter()時,outter便直接叫用inner(7)49列印出來,此時inner被叫用於在outter函式中但被宣告定義之前。

  然後我們用閉包的方式把latter函式指到inner,由於閉包會把inner的相關內容複製保留下來,所以呼叫latter時,latter可以直接叫用inner的所有可視變數(包括inner的外部函式變數c),因此在outter之後,呼叫latter()latter(8)都可以成功列印出158的平方。

  最後我們在測試完閉包後,直接呼叫inner(),答案自然是GG了,因為該函式只在它的外部函式outter內為可視,你跑到外面來自然是看不到這東西,所以程式回應inner未被定義,也就是不存在的意思。

Sample 2.

var latter

function outter() {

    var c = 15

 

    console.log("outter呼叫內部函式inner在定義宣告inner(x)之前!")

    console.log("inner(7) = " + inner(7))

 

    function inner(x=c) {

        return x*x

    }

 

    latter = inner //建立閉包

    console.log("outter呼叫內部函式inner在定義宣告inner(x)之後!")

    console.log("inner() = " + inner())

}

 

outter()

console.log("用閉包latter()呼叫inner() : " )

console.log(latter())

console.log("用閉包latter(8)呼叫inner(8) : " )

console.log(latter(8))

 

try {

    console.log("outter外呼叫內部函式inner() : ")

    console.log(inner())

} catch(e) {

    console.log("Error: " + e.message)

}

 

Sample 2 執行結果:

  以上兩個Sample被我整合在同一支程式並上傳到Git Hub上,測試使用node js執行程式,歡迎大家下載測試唷:https://github.com/jackterrylau/SchoolCode/blob/master/Javascript/scope_test.js

 

201993日星期二

arrow
arrow
    創作者介紹
    創作者 jackterrylau 的頭像
    jackterrylau

    儒道哲學的浪漫人生

    jackterrylau 發表在 痞客邦 留言(0) 人氣()