JavaScript Tips
這個系列會把每天讀到、看到、想到、聽到、夢到關於 JavaScript 的技巧記錄下來,所以會比較零碎...maybe 等過了幾天後,會針對各主題整理出完整文章
Primitive Types and Object Types
基本型別(Primitive Types)
- number
- string
- boolean
- null
- undefined
- symbol
物件型別(Object Types)
- array
- function
- date
- map
一般來說,基本型別(Primitive Types)會是 call by value,而物件型別(Object Types)則是 call by reference。
Call by value
var x = "foo";
var y = "bar";
var a = x;
var b = y;a = 123;
b = "xyz";console.log(x, y, a, b) // foo bar 123 xyz
當 var a = x 時,實際上是把 x 的值複製給了 a,所以其實 a 和 x 都是獨立的不互相影響。
Call by reference
var foo = [1];
var bar = foo;foo.push(2);
console.log(foo, bar); // [1, 2] [1, 2]
當 foo 被宣告時,會在記憶體的某處建立一個物件,並將 foo 指向這個物件。接著 var bar = foo 的時候,就是讓 foo 把相同的指向再傳給 bar。 此時兩個變數都是指向同個物件了,因此對這個物件的所有操作,都會同時影響到 foo 和 bar。
再看一題
function foo(bar) {
this.a = bar;
this.b = new Array(bar[0], bar[1], bar[2]);
}const bar = [10, 10, 10];
const zzz = new foo(bar);bar[0] = 100;
bar[3] = 100;console.log(bar[0] + zzz.a[3] + zzz.b[0]); // 210
typeof
typeof null; // 'object'
typeof undefined; // 'undefined'typeof function() {}; // 'function'
typeof [1, 2, 3]; // 'object'typeof NaN; // 'number'
除了平常常看到型態以外,以上這幾種結果需要特別注意
Scope
指的是當前的執行上下文。值和表達式在其中 “可見” 或可被訪問到的上下文。
如果一個變數或者其他表達式不 “在當前的作用域中”,那麼它就是不可被使用的。
作用域也可以根據程式碼層次分層,以便子作用域可以訪問父作用域,通常是指沿著鍊式的作用域鏈查找,而不能從父作用域引用子作用域中的變數和引用。
當然,一個 Function 將生成一個閉包(通常是返回一個函數引用),這個函數引用從外部作用域(在當前環境下)可以訪問閉包內部的作用域。例如,下面的代碼是無效的,並不是閉包的形式):
function foo() {
var x = "hello world"; // x 只能在 foo 函数中使用
console.log(x);
}
console.log(x); // error
但是,由於變數在函數外被聲明為全局變數,因此下面的代碼是有效的(當前作用域不存在的變數和引用,就沿著作用域鏈繼續尋找):
var x = "hello world";
foo();
function foo() {
console.log("Inside function");
console.log(x);
}
console.log("Outside function");
console.log(x);
Hoisting(拉升)
編譯器會由上到下逐行將程式碼轉為電腦可懂的命令,在這個編譯的階段,編譯器找出所有的變數並繫結所屬範疇,但不賦值,所以此刻變數所帶的值是 undefined;而在執行階段,JavaScript 引擎才會處理給值的事情。
JavaScript 在執行任何程式碼前,會將函數宣告放入記憶體中的優點之一是,你可以在宣告一個函數之前使用該函數。例如:
var foo;
console.log(foo); // undefinedfoo = 2;
JavaScript 只會拉升宣告,不會拉升其初始化。如果一個變數先被使用再被宣告和賦值的話,使用時的值是 undefined。如果你先賦值、再使用、最後宣告該變數,使用時能獲取到所賦的值
foo = 2;console.log(foo); // 2var foo;
即刻調用函式運算式(Immediately Invoked Function Expression, IIFE)
IIFE 是一個在定義時就會立即執行的 JavaScript 函數。使用 IIFE 的好處主要是不污染全域範疇。
(function () {
var name = "foo";
})();
name // error