JavaScript ES6
let & const
- 变量严格只在作用域里有效
- 不能多次重复声明
- 内层可以声明外层的变量, 但改变不了外部的变量
- 必须先声明再使用(死区)
- (let, const都遵循)
const指向的地址, 如果const指向了一个对象, 那么对象不能被替换(因为地址变了), 但对象的内容可以变化 比如指向了一个给对象, 那么对象的属性可以改变, 指向一个数组, 数组可以增删 但都不能真能赋新值
如果要冻结对象:
const foo = Object.freeze({});
// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;
将一个对象连同属性彻底冻结:
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key, value) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};
全局对象
- 在浏览器中指的是 windows 对象, 在 node.js 中指的是 global 对象
- ES6中, let, const, class定义的对象, 不再是全局对象
解构赋值
let [head, ...tail] = [1, 2, 3, 4];
// head // 1
// tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
// x // "a"
// y // undefined // 解构不成功的会成为undefined
// z // []
- 事实上,只要某种数据结构具有
Iterator接口,都可以采用数组形式的解构赋值。否则就不行
function* fibs() {
var a = 0;
var b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
var [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
- 解构赋值可以有默认值, 默认值也可以是函数, 但是是惰性求值的, 如果有值, 则不会触发函数
function f() {
console.log('aaa');
}
let [x = f()] = [1]; // f()根本不会执行 // 定义一个数组,并且给里面一个元素命名为x
- 解构不仅可以用于数组,还可以用于对象。
var { foo, bar } = { foo: "aaa", bar: "bbb" };
// foo: "aaa"
// bar: "bbb"
// 给对象赋值要注意
var { foo: baz } = { foo: "aaa", bar: "bbb" };
// baz: “aaa” // foo的结果用baz接,然后我们传的是aaa
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
// f: 'hello'
// last: 'world'
// 干脆这么理解,我要一个f,一个l,值分别来自于obj对象的first和last
- 对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。 这一节比较猛,多留意一下
let { log, sin, cos } = Math;
上面代码将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。
- 属性赋值:
let {length : len} = 'hello';
// len: 5
// length: 3 (???) 难道不是我要一个len,值来自于'hello`字符串的lengh属性吗?
- 函数参数的解构也可以使用默认值。
function move({x = 0, y = 0} = {}) { // 双重默认值,飒,即给一个空值就默认为传{}
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
// 为了理解深刻点,我们把不传时的默认值改一下
function move({x = 0, y = 0} = {y:77}) { // 双重默认值,飒,即给一个空值就默认为传{}
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 77] // ««« 唯一的区别在这里
上面代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值。 注意,下面的写法会得到不一样的结果。
function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
// 这一次,不给对象赋默认值了,只有完全不给对象,才会给默认值
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
所以我说双重默认值,一个是空对象的默认值,一个是有对象的话,里面的属性的默认值
undefined就会触发函数参数的默认值。
[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]
模板字符串嵌套
const tmpl = addrs => `
<table>
${addrs.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}
</table>
`;
- 如果需要引用模板字符串本身,在需要时执行,可以像下面这样写。
// 写法一
let str = 'return ' + '`Hello ${name}!`';
let func = new Function('name', str);
func('Jack') // "Hello Jack!"
// 写法二
let str = '(name) => `Hello ${name}!`';
let func = eval.call(null, str);
func('Jack') // "Hello Jack!"
我只能看懂写法2...
正则
- 点(.)字符在正则表达式中,含义是除了换行符以外的任意单个字符。
- 对于码点大于
0xFFFF的Unicode字符,点字符不能识别,必须加上u修饰符。
var s = '𠮷';
/^.$/.test(s) // false
/^.$/u.test(s) // true
y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。- 同之处在于,
g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
- 同之处在于,
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]
r1.exec(s) // ["aa"]
r2.exec(s) // null
- 注意, 是对exec方法而言!!!
- 进一步说,y修饰符号隐含了头部匹配的标志^。
/b/y.exec('aba')
// null
上面代码由于不能保证头部匹配,所以返回null。y修饰符的设计本意,就是让头部匹配的标志^在全局匹配中都有效。
单单一个y修饰符对match方法,只能返回第一个匹配,必须与g修饰符联用,才能返回所有匹配。(我们会以为例子中的值是a\d连续的, 所以会被y匹配到, 并不是)
'a1a2a3'.match(/a\d/y) // ["a1"]
'a1a2a3'.match(/a\d/gy) // ["a1", "a2", "a3"]
数组
Array.from方法则是还支持类似数组的对象。- 所谓类似数组的对象,本质特征只有一点,即必须有
length属性。 - 因此,任何有length属性的对象,都可以通过
Array.from方法转为数组,而此时扩展运算符就无法转换。
- 所谓类似数组的对象,本质特征只有一点,即必须有
Array.from({ length: 3 });
// [ undefined, undefined, undefinded ]
Array.from("hello");
// ['h', 'e', 'l', 'l', 'o']
Array.of方法用于将一组值,转换为数组。
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
- 这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。
Array() // []
Array(3) // [, , ,] // (3)理解为了个数
Array(3, 11, 8) // [3, 11, 8] // (3)理解为了值
- 注意判断NaN的用法
[NaN].findIndex(y => Object.is(NaN, y))
如何import
import _ from "lodash";
这种简略的表达方法等价于
import {default as _} from "lodash"
refs: Spread Syntax