js 引擎解析方式:
會先搜尋 function
關鍵字,為行開頭、或在分號後面時,會直接在記憶體中建立函式,為陳述式。
再上到下掃描,遇到var
為讀到該行,才會建立函式位置,為表達式。
// 陳述式
function hi (){ ... }
// 呼叫 函式名稱 + ()
hi()
// 表達式:為「匿名函式」賦值給變數,變數會指引到 function 儲存位置。
var hoo = function(){ ... }
// 呼叫 變數名稱 + ()
hoo()
查看物件值:可以 console.log 該物件名稱, 名稱記著「地址」,去地址找到物件「值」。
console.log 一個 function 名稱, 會印出整個 function Object;
但 function 物件,有幾個特殊的屬性:
()
來帶參數、執行函式。若為「陳述式」則是特殊屬性的 function name + ()
。
若為「表達式」,會是那個 var
變數名稱 + ()
。
// 一個表達式:程式碼解析到該行,才建立函式、建立後立刻執行。
var hoo = function(n){
return 30 + n;
}()
// hoo 會得到 30+n 後的值:
// 匿名函式如何執行:
(function(){ ... }())
// 裝成「表達式」,否則執行 js 會產生語法錯誤
.js
中允許「表達式」存在那裡,不做事,也不會回傳錯誤。
但 function
關鍵字,若出現在一行開頭、;
後第一個字,
會被判斷為一「 funtion 陳述式」,被要求後面接 function 名稱,
不可是匿名的,否則會出現語法錯誤。
()
是運算子,在 js 中認為 ()
為「表達式」,
所以 ( function ... )
會被判定為一個表達式的存在,
這樣我們讓 function 像其他值一樣,作為表達式存在,
IIFE 被 ()
包住,可以在 js 執行時不報語法錯誤。
function 執行時,建立了「執行環境」並「生成了」相關的變數,
是一個
閉包結構,就像模組化。
檔案 hello.js:
var s = 'Hello'; // 全域的
var name = 'world';
function greet(name) {
console.log(s + ' ' + name + '!');
}
檔案 hello.js node 會轉為這樣執行:
(function (module) {
var s = 'Hello'; // 閉包
var name = 'world';
function greet(name) {
console.log(s + ' ' + name + '!');
}
module.exports = greet;
})(module);
http://jsbin.com/zisevaj/edit?js,console
// Node 准备了一个变數 (#hello) module
var module = {
id: 'hello',
exports: {}
};
// Node load 函式,
// 用 `load()` 為 (#hello) `module` 新增 hello.js 中的 `greet` 方法,
var load = function (module) {
// ----------------------- hello.js code
function greet(name) {
console.log('Hello, ' + name + '!');
}
// `module` 是 `load()` 傳入的,故 hello.js 可以讀到
module.exports = greet;
// ----------------------- # hello.js code
// 傳出 (#hello) module.exports = greet 方法
return module.exports;
};
// 將此方法 (#hello) module.exports 存到 exported 變數中
var exported = load(module);
// Node 会把 module 变量保存到某个地方。
save(module, exported);
由于 Node 保存了所有导入 load() 的 (#hello) module 当我们用 require() 获取 (#hello) module 时, Node 返回这个 module 的 exports 变量,
var greet = require('./hello');
这样,另一个模块就顺利拿到了模块的输出