2017_12-第三周

2017_12-第三周

const关键字

const:此声明创建一个常量,其作用域可以是全局或本地声明的块。 与var变量不同,全局常量不会变为窗口对象(widows)的属性。需要一个常数的初始化器;也就是说,您必须在声明的同一语句中指定它的值(这是有道理的,因为以后不能更改)。

const声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。例如,在引用内容是对象的情况下,这意味着可以改变对象的内容(例如,其参数)。^1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// 注意: 常量在声明的时候可以使用大小写,但通常情况下全部用大写字母。 

// 定义常量MY_FAV并赋值7
const MY_FAV = 7;

// 报错
MY_FAV = 20;

// 输出 7
console.log("my favorite number is: " + MY_FAV);

// 尝试重新声明会报错
const MY_FAV = 20;

// MY_FAV 保留给上面的常量,这个操作会失败
var MY_FAV = 20;

// 也会报错
let MY_FAV = 20;

// 注意块范围的性质很重要
if (MY_FAV === 7) {
// 没问题,并且创建了一个块作用域变量 MY_FAV
// (works equally well with let to declare a block scoped non const variable)
let MY_FAV = 20;

// MY_FAV 现在为 20
console.log('my favorite number is ' + MY_FAV);

// 这被提升到全局上下文并引发错误
var MY_FAV = 20;
}

// MY_FAV 依旧为7
console.log("my favorite number is " + MY_FAV);

// 常量要求一个初始值
const FOO; // SyntaxError: missing = in const declaration

// 常量可以定义成对象
const MY_OBJECT = {"key": "value"};

// 重写对象和上面一样会失败
MY_OBJECT = {"OTHER_KEY": "value"};

// 对象属性并不在保护的范围内,下面这个声明会成功执行
MY_OBJECT.key = "otherValue";

// 也可以用来定义数组
const MY_ARRAY = [];
// It's possible to push items into the array
// 可以向数组填充数据
MY_ARRAY.push('A'); // ["A"]
// 但是,将一个新数组赋给变量会引发错误
MY_ARRAY = ['B']

let关键字

let语句声明一个块级作用域的本地变量,并且可选的将其初始化为一个值。^2

作用域规则

let声明的变量只在其声明的块或子块中可用,这一点,与var相似。二者之间最主要的区别在于var声明的变量的作用域是整个封闭函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function varTest() {
var x = 1;
if (true) {
var x = 2; // 同样的变量!
console.log(x); // 2
}
console.log(x); // 2
}

function letTest() {
let x = 1;
if (true) {
let x = 2; // 不同的变量
console.log(x); // 2
}
console.log(x); // 1
}

简化内部函数代码

当用到内部函数的时候,let会让你的代码更加简洁,,对比之前[立即执行函数表达式(IIFE)]。(https://someoneiscoding.github.io/2017/12/10/%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8C%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%28IIFE%29/#iife)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var list = document.getElementById('list');

for (let i = 1; i <= 5; i++) {
let item = document.createElement('li');
item.appendChild(document.createTextNode('Item ' + i));

item.onclick = function(ev) {
console.log('Item ' + i + ' is clicked.');
};
list.appendChild(item);
}

// to achieve the same effect with 'var'
// you have to create a different context
// using a closure to preserve the value
// 要用var关键字实现同样的功能,你不得不使用闭包来维护不同的上下文环境以保护值(不被改变)。
for (var i = 1; i <= 5; i++) {
var item = document.createElement('li');
item.appendChild(document.createTextNode('Item ' + i));

(function(i){
item.onclick = function(ev) {
console.log('Item ' + i + ' is clicked.');
};
})(i);
list.appendChild(item);
}

↑ 以上示例的工作原理是因为(匿名)内部函数的五个实例引用了变量i的五个不同实例。注意,如果你将let替换为var,则它将无法正常工作,因为所有内部函数都将返回相同的i=6的最终值。此外,我们可以通过将创建新元素的代码移动到每个循环的作用域来保持循环更清晰。

在程序或者函数的顶层,let并不会像var一样在全局对象上创造一个属性,比如:👇

1
2
3
4
var x = 'global';
let y = 'global';
console.log(this.x); // "global"
console.log(this.y); // undefined

let暂存死区的错误

在 ECMAScript 2015 中,let绑定不受变量提升的约束,这意味着let声明不会被提升到当前执行上下文的顶部。在块中的变量初始化之前,引用它将会导致ReferenceError(而使用var声明变量则恰恰相反,该变量的值是undefined)。该变量处于从块开始到初始化处理的“暂存死区”。👇

1
2
3
4
5
6
function do_something() {
console.log(bar); // undefined
console.log(foo); // ReferenceError: foo is not defined
var bar = 1;
let foo = 2;
}

由于词法作用域,表达式(foo + 55)内的标识符foo会解析为if块的foo,而不是覆盖值为33的foo。在这一行中,if块的foo已经在词法环境中创建,但尚未达到(并终止)其初始化(这是语句本身的一部分):它仍处于暂存死区。👇

1
2
3
4
5
6
7
function test(){
var foo = 33;
if (true) {
let foo = (foo + 55); // ReferenceError
}
}
test();

字面量 (Literals)

(译注:字面量是由语法表达式定义的常量;或,通过由一定字词组成的语词表达式定义的常量)^3

在JavaScript中,你可以使用各种字面量。这些字面量是脚本中按字面意思给出的固定的值,而不是变量。(译注:字面量是常量,其值是固定的,而且在程序脚本运行中不可更改,比如false,3.1415,thisIsStringOfHelloworld ,invokedFunction:myFunction(“myArgument”)。

1
var fish = ["Lion", , "Angel"];

👆在这个数组中,有两个已被赋值的元素,和一个空元素(fish[0]是”Lion”,fish[1]是undefined,而fish[2]是”Angel”;译注:此时数组的长度属性fish.length是3)。

如果你在元素列表的尾部添加了一个逗号,它将会被忽略。在下面的例子中,数组的长度是3,并不存在myList[3]这个元素(译注:这是指数组的第4个元素噢,作者是在帮大家复习数组元素的排序命名方法)。元素列表中其它所有的逗号都表示一个新元素(的开始)。👇

1
2
var myList = ['home', , 'school', ];
// 尾部的逗号在早期版本的浏览器中会产生错误,因而编程时的最佳实践方式就是移除它们。


2017-12-20

ci:Case Insensitive, 即 “大小写不敏感”, a 和 A 会在字符判断中会被当做一样的。
utf8_unicode_ci和utf8_general_ci对中、英文来说没有实质的差别。
utf8_general_ci校对速度快,但准确度稍差。
utf8_unicode_ci准确度高,但校对速度稍慢。

如果你的应用有德语、法语或者俄语,请一定使用utf8_unicode_ci。一般用utf8_general_ci就够了。