-
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"