ES6项目构建
好用的一些功能
1 | 1、数组去重 |
基本知识点
let和const命令
let命令
let声明1
2
3
4
5
6{
let a=10;//let声明的变量只在它所在的代码块有效
var b=1;
}
console.log(b);
// console.log(a);//报错
let应用
1 | for(let i=0;i<10;i++){} |
let不支持变量提升
只要块级作用域内存在let命令,它所声明的变量就“绑定”了这块区域,不再受外部的影响
1 | var temp=123; |
块级作用域
外层作用域无法读取内层作用域的变量
1 | {{{{ |
内层作用域可以定义外层作用域的同名变量
1 | {{{{ |
作用:使的获得广泛应用的立即执行函数表达式(IIFE)不再必要了
1 | // IIFE 写法 |
do 表达式
块级作用域本质上是语句,没有返回值,所以在外部没法或许执行结果
可以通过do表达式获取块级作用于中的最后执行的表达式的值。
1 | let x = do{ |
const 命令
const 声明一个只读的常量。一旦声明,常量的值就不能改变。—所以常量一旦声明就必须立即初始化,不能留到以后赋值
const 的作用域与let命令相同:只在声明所在的块级作用域内有效
const 命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
const实际保证的,并不是变量的值不得改动,而是变量指向的哪个地址不得改动
如:const foo={};
foo存的是地址,这个地址指向一个对象,这个对象本身是可变的,故可添加属性foo.prop=123;
但是不可把foo指向另一个地址:foo = {}//错误
————-让对象冻结的方法(不可改变属性)—————1
2const foo=Object freeze({});
foo.prop=123;//常规模式下,此行代码不起作用。 严格模式下会报错
————-让对象彻底冻结的方法————————-
注:对象的属性有可能还是对象,那么对象的属性就有可能有自己的属性,那么对象的属性也要被冻结
***使用回调函数
1 | var constantize = (obj)=>{ |
es6声明变量的6种方法
var function let const import class es5只有前两种
顶层对象的属性
顶层对象:window(浏览器环境),global(Node环境)
window.a=1; 和 a=1; 是一样的,即顶层对象属性和全局变量是一样的
这是JavaScript设计的败笔之一,ES6为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。
1 | var a = 1; |
global对象
有一个提案,在语言标准的层面,引入global作为顶层对象。也就是说,在所有环境下,global都是存在的,都可以从它拿到顶层对象
垫片库(system.global)模拟了这个提案,可以在所有环境中拿到global
1 | import getGlobal from 'system.global'; |
变量的解构赋值
数组的解构赋值
1 | let [foo, [[bar], baz]] = [1, [[2], 3]]; |
如果解构不成功,变量的值就等于undefined。
1 | let [foo] = []; |
以上两种情况都属于解构不成功,foo的值都会等于undefined。
不完全解构:
1 | let [x, y] = [1, 2, 3];// x 为1, y为2 |
//下面情况将会报错,右边必须为数组(可遍历的结构——Iterator 接口)形式
1 | let [foo] = 1; |
对于 Set 结构,也可以使用数组的解构赋值。
1 | let [x, y, z] = new Set(['a', 'b', 'c']); |
事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
1 | function* fibs() { |
默认值
解构赋值允许指定默认值
1 | let [foo = true] = []; |
ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。1
2
3
4let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null
如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。
==惰性求值==:即只有在用到的时候才会求值
默认值可以引用解构赋值的其他变量,但该变量必须已经声明1
2
3let [x = 1, y = x] = []; // x=1; y=1
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError
对象的解构赋值
数组的解构赋值是有顺序的,但是对象的解构赋值是无需的,变量名和属性同名才能获取到正确的值。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15let { bar: bar, foo: foo } = { foo: "aaa", bar: "bbb"};
// 可以简写为
let { bar, foo } = { foo: "aaa", bar: "bbb"};
foo // "aaa"
bar // "bbb"
let {foo: xiao , baz } = { foo: "aaa", bar: "bbb"};
baz // undefined
xiao // "aaa"
//真正被赋值的是后者
foo // error : foo is not defined
let obj = { first: 'hello', last: 'world' };
let { first: f, last: 1 } = obj;
f // 'hello'
l // 'world'
与数组一样,结构也可以用于嵌套结构的对象1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
//如果写法如下:那么p既是模式又是变量
let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]
一个嵌套的例子:
1 | let obj = {}; |
对象的结构也可以设置默认值,默认值生效的条件是严格等于undefined
如果结构失败,变量的值等于undefined
1 | var { x = 1, y = 2 } = { x: undefined, y: null }; |
对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量1
2
3let {sin, cos, tan} = Math;
Math.sin // 一个sin function
sin // 一个sin function 直接将Math中的方法给了sin
字符串的解构赋值
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象1
2
3
4
5
6
7const [a, b, c, d, e] = 'hello';
a // "h"
e // "o"
//类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值
let {length : len} = 'hello';
len // 5
数值和布尔值得解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象,无法转化成对象,将会报错1
2
3
4
5
6
7
8let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
函数参数的解构赋值
1 | function add([x, y]){ |
undefined就会触发函数参数的默认值。1
2[1, undefined, 3].map((x = 'yes') => x);
// [ 1, 'yes', 3 ]
圆括号问题
建议只要有可能,就不要在模式中放置圆括号
不能使用圆括号的情况
1.变量声明语句1
2
3
4
5
6
7//全部报错
let [(a)] = [1];
let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
2.函数参数1
2
3
4// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }
3.赋值语句模式1
2
3
4
5
6// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];
// 报错
[({ p: a }), { x: c }] = [{}, {}];
可以使用圆括号的情况
只有一种:赋值语句的非模式部分,可以使用圆括号1
2
3[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确
用途
1.交换变量的值1
2
3let x = 1;
let y =2;
[x, y] = [y, x];
2.从函数返回多个值
直接取值就可以1
2
3
4
5
6
7function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
3.函数参数的定义
4.提取JSON数据1
2
3
4
5
6
7
8let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
5.函数参数的默认值1
2
3
4
5
6
7
8
9
10
11jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) {
// ... do stuff
};
指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || ‘default foo’;这样的语句
6.遍历Map结构1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world
//如果只想获取键名,或者只想获取键值,可以写成下面这样。
// 获取键名
for (let [key] of map) {
// ...
}
// 获取键值
for (let [,value] of map) {
// ...
}
7.输入模块的指定方法
加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。1
const { SourceMapConsumer, SourceNode } = require("source-map");
字符串的扩展
字符的Unicode表示法
codePointAt()
String.fromCodePoint()
字符串的遍历器接口
es6为字符串添加了遍历器接口,而且增加的for…of循环识别码点1
2
3
4
5
6
7
8
9
10
11let text = String.fromCodePoint(0x20BB7);
for (let i of text) {
console.log(i);
}
// "𠮷"
for (let i = 0; i < text.length; i++) {
console.log(text[i]);
}
// " "
// " "
at()
es5中的charAt方法可以返回字符串指定位置的字符,但是不识别码点大于0xFFFF的字符。es6提供了at()方法,可以实现这一要求1
2
3
4'abc'.charAt(0) //"a"
'𠮷'.charAt(0) // "\uD842"
'abc'.at(0) // "a"
'𠮷'.at(0) // "𠮷"
normalize()
includes()、startWith()、endsWith
includes():返回布尔值,表示是否找到了参数字符串。
startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。1
2
3
4
5
6
7
8
9
10let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
//这三个方法都支持第二个参数,表示开始搜索的位置。
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
repeat()
repeat方法返回一个新字符串,表示将原字符串重复n次。1
'hello'.repeat(2) // "hellohello"
padStart(),padEnd()
字符串补全长度的功能9
