-
for
循環中的let
,在for
頭部中的let i
不僅是為for
循環本身聲明了一個i
,而且它為循環的每一次迭代都重新聲明了一個新的i
var funcs = [];
for (let i = 0; i < 5; i++) {
funcs.push( function(){
console.log( i );
} );
}
funcs[3](); // 3
- 將一個對象或數組作為常量賦值意味著這個值在常量的詞法作用域消失以前是不能夠被垃圾回收的,因為指向這個值的引用是永遠不能解除的。這可能是你期望的,但如果不是你就要小心!
-
const
用還是不用
有些流傳的猜測認為在特定的場景下,與let
或var
相比一個const
可能會被JS引擎進行更多的優化。理論上,引擎可以更容易地知道變量的值/類型將永遠不會改變,所以它可以免除一些可能的追蹤工作。
無論const
在這方面是否真的有幫助,還是這僅僅是我們的幻想和直覺,你要做的更重要的決定是你是否打算使用常量的行為。記住:源代碼扮演的一個最重要的角色是為了明確地交流你的意圖是什么,不僅是與你自己,而且還是與未來的你和其他的代碼協作者。
一些開發者喜歡在一開始將每個變量都聲明為一個const
,然后當它的值在代碼中有必要發生變化的時候將聲明放松至一個let
。這是一個有趣的角度,但是不清楚這是否真正能夠改善代碼的可讀性或可推理性。
就像許多人認為的那樣,它不是一種真正的 保護,因為任何后來的想要改變一個const
值的開發者都可以盲目地將聲明從const
改為let
。它至多是防止意外的改變。但是同樣地,除了我們的直覺和感覺以外,似乎沒有客觀和明確的標準可以衡量什么構成了“意外”或預防措施。這與類型強制上的思維模式類似。
我的建議:為了避免潛在的令人糊涂的代碼,僅將const
用于那些你有意地并且明顯地標識為不會改變的變量。換言之,不要為了代碼行為而 依靠 const
,而是在為了意圖可以被清楚地表明時,將它作為一個表明意圖的工具。
- 函數默認值表達式
function bar(val) {
console.log( "bar called!" );
return y + val;
}
function foo(x = y + 3, z = bar( x )) {
console.log( x, z );
}
var y = 5;
foo(); // "bar called"
// 8 13
foo( 10 ); // "bar called"
// 10 15
y = 6;
foo( undefined, 10 ); // 9 10
- 解構默認值 + 參數默認值
function f6({ x = 10 } = {}, { y } = { y: 10 }) {
console.log( x, y );
}
f6(); // 10 10
f6( {}, {} ); // 10 undefined
- 標簽型模板字面量
function foo(strings, ...values) {
console.log( strings );
console.log( values );
}
var desc = "awesome";
foo`Everything is ${desc}!`;
// [ "Everything is ", "!"]
// [ "awesome" ]
-
symbol
實現的單例模式
const INSTANCE = Symbol( "instance" );
function HappyFace() {
if (HappyFace[INSTANCE]) return HappyFace[INSTANCE];
function smile() { .. }
return HappyFace[INSTANCE] = {
smile
};
}
var me = HappyFace(),
you = HappyFace();
me === you; // true
- 數組的強制轉換比較會使用
tostring()
方法,使用逗號(,
)連接所有值來被強制轉換為string
var a = [1,2,3];
var b = [1,2,3];
var c = "1,2,3";
a == c; // true
b == c; // true
a == b; // false
-
this
指向
function foo() {
console.log( this.bar );
}
var bar = "global";
var obj1 = {
bar: "obj1",
foo: foo
};
var obj2 = {
bar: "obj2"
};
// --------
foo(); // "global"
obj1.foo(); // "obj1"
foo.call( obj2 ); // "obj2"
new foo(); // undefined
- typeof
var a;
typeof a; // "undefined"
typeof b; // "undefined" b并沒有被聲明,但是不會報錯,這是 typeof 的一種特殊的安全防衛行為
- 日期的轉換時間戳
+new Date();
new Date().getTime();
Date.now(); // ES6
-
~
按位取反,~x
大致與-(x+1)
相同
if (~a.indexOf( "lo" )) { // true
// 找到了!
}
- 整數的小數位截斷
~~-49.6;
-43.2 | 0
- 數字的解析和強制轉換不一樣
var b = "42px";
Number( b ); // NaN
parseInt( b ); // 42,ps:parseInt(..)工作在`string`值上,如果是非字符串,會先`toString()`
- 基本數據的創建和使用時會自動
封箱
和拆(開)箱
-
==
和===
錯誤說法: `==`檢查值的等價性,而`===`檢查值和類型的等價性
正確說法:`==`允許在等價性比較中進行強制轉換,而`===`不允許強制轉換
- 一個古怪的題目
a == 2 && a == 3
var i = 2;
Number.prototype.valueOf = function() {
return i++;
};
var a = new Number( 0 );
if (a == 2 && a == 3) {
console.log( "Yep, this happened." );
}
- 常用真假比較
"0" == null; // false
"0" == undefined; // false
"0" == false; // true -- 噢!
"0" == NaN; // false
"0" == 0; // true
"0" == ""; // false
false == null; // false
false == undefined; // false
false == NaN; // false
false == 0; // true -- 噢!
false == ""; // true -- 噢!
false == []; // true -- 噢!
false == {}; // false
"" == null; // false
"" == undefined; // false
"" == NaN; // false
"" == 0; // true -- 噢!
"" == []; // true -- 噢!
"" == {}; // false
0 == null; // false
0 == undefined; // false
0 == NaN; // false
0 == []; // true -- 噢!
0 == {}; // false
[] == ![]; // true
2 == [2]; // true
"" == [null]; // true
0 == "\n"; // true
- 語言規范,對于
a <= b
,它實際上首先對b < a
求值,然后反轉那個結果 finally
function baz() {
try {
return 42;
}
finally {
// 覆蓋前面的 `return 42`
return "Hello";
}
}
baz(); // "Hello"
- 如何創建
空
對象
Object.create( null ) // 比{}更空,它沒有指向 `Object.prototype` 的委托
- 數字轉別的進制
var a = 42;
a.toString(); // "42" —— 也可使用`a.toString( 10 )`
a.toString( 8 ); // "52"
a.toString( 16 ); // "2a"
a.toString( 2 ); // "101010"