一、let和const
1、let
let用来声明局部变量,用法类似于var,但是没有变量提升。
2、const
const声明一个只读的常量。一旦声明,常量的值就不能改变。
3、块级作用域
块状作用域解决了内层变量可能会覆盖外层变量,用来计数的循环变量泄露为全局变量的问题
二、解构赋值
解构不成功,变量的值就等于undefined。
var [a, b, c] = [1, 2, 3];
let [ , , third] = ["foo", "bar", "baz"];
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
var { foo, bar } = { foo: "aaa", bar: "bbb" };
// 重命名,前面的键名为匹配模式不是变量
var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // foo is not defined
// 指定默认值
var {x, y = 5} = {x: 1};
x // 1
y // 5
// 默认值生效的条件是,对象的属性值严格等于`undefined`。
var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null
等号的右边不是数组(或者严格地说,不是可遍历的结构),那么将会报错。
Set结构也可以解构赋值,事实上,只要某种数据结构具有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();
解构赋值指定默认值必须值为undefined
三、字符串扩展
codePointAt()
codePointAt方法会正确返回32位的UTF-16字符的码点。
// 𠮷为4个字节储存的字符
var s = "𠮷";
// p为2个字节储存的字符
let p = "a";
console.log(
s.codePointAt(0),
s.codePointAt(1),
s.charCodeAt(0),
p.codePointAt(0),
p.charCodeAt(0)
);
// 134071 57271 55362 97 97
字符串的遍历器接口
字符串可以被for...of循环遍历。
for (let codePoint of 'foo') {
console.log(codePoint)
}
// "f"
// "o"
// "o"
at()
返回字符串给定位置的字符,同es5charAt方法,charAt不能识别码点大于0xFFFF的字符。
// 识别码点大于`0xFFFF`的字符。
'abc'.at(0) // "a"
includes(), startsWith(), endsWith()
- includes() :返回布尔值,表示是否找到了参数字符串。
- startsWith() :返回布尔值,表示参数字符串是否在源字符串的头部。
- endsWith() :返回布尔值,表示参数字符串是否在源字符串的尾部。
var 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
第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。
repeat()
repeat方法返回一个新字符串,表示将原字符串重复n次。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
参数如果是小数,会被取整。参数是负数或者Infinity,会报错
'na'.repeat(2.9)
'na'.repeat(Infinity)
// RangeError
'na'.repeat(-1)
// RangeError
padStart(),padEnd()
串补全长度的功能,padStart用于头部补全,padEnd用于尾部补全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
模板字符串
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
标签模板
模板字符串可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。
alert`123`
// 等同于
alert(123)
Symbol
Symbol为新的原始数据类型Symbol,表示独一无二的值。用于防止属性名的冲突,导致属性被覆盖删除等。
Set和Map结构
Set
Set基础
Set无重复数组,类似与数组结构,Set中NaN唯一,及两个NaN只能添加为一个。Set可用for of遍历循环。
var s = new Set();
[2, 3, 5, 4, 5, 2, 2].map(x => s.add(x));
for (let i of s) {
console.log(i);
}
// 2 3 5 4
Set实例的属性和方法
Set.prototype.constructor:构造函数,默认就是Set函数。Set.prototype.size:返回Set实例的成员总数。
Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
add(value):添加某个值,返回Set结构本身。delete(value):删除某个值,返回一个布尔值,表示删除是否成功。has(value):返回一个布尔值,表示该值是否为Set的成员。clear():清除所有成员,没有返回值。
遍历操作
keys():返回键名的遍历器values():返回键值的遍历器entries():返回键值对的遍历器forEach():使用回调函数遍历每个成员 Set没有键名,故keys()和values()行为一致
WeakSet
WeakSet基础
WeakSet结构与Set类似,WeakSet的成员只能是对象。而且WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。这个特点意味着,无法引用WeakSet的成员,因此WeakSet是不可遍历的。
WeakSet实例的属性和方法
WeakSet结构有以下三个方法。
- WeakSet.prototype.add(value) :向WeakSet实例添加一个新成员。
- WeakSet.prototype.delete(value) :清除WeakSet实例的指定成员。
- WeakSet.prototype.has(value) :返回一个布尔值,表示某个值是否在WeakSet实例之中。
var ws = new WeakSet();
var obj = {};
var foo = {};
ws.add(window);
ws.has(window); // true
ws.delete(window);
Map
Map基础
var items = [
['name', '张三'],
['title', 'Author']
];
var map = new Map();
items.forEach(([key, value]) => map.set(key, value));
如果对同一个键多次赋值,后面的值将覆盖前面的值。
let map = new Map();
map
.set(1, 'aaa')
.set(1, 'bbb');
map.get(1) // "bbb"
Map实例的属性和方法
Map.prototype.size:返回Set实例的成员总数。
Set实例的方法分为两大类:操作方法(用于操作数据)和遍历方法(用于遍历成员)。下面先介绍四个操作方法。
set(key, value):set方法设置key所对应的键值,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。get(key):get方法读取key对应的键值,如果找不到key,返回undefined。delete(key):delete方法删除某个键,返回true。如果删除失败,返回false。has(key):has方法返回一个布尔值,表示某个键是否在Map数据结构中。clear():清除所有成员,没有返回值。
const a = { a: 1 };
let map = new Map().set(a, "a111").set(2, "b");
a.a = 2;
map.get(a); // a111
map.has(a); // true
map.delete(a);
map.has(a); // false
map.clear();
map.has(2); // false
遍历方法
Map原生提供三个遍历器生成函数和一个遍历方法。
keys():返回键名的遍历器。values():返回键值的遍历器。entries():返回所有成员的遍历器。forEach():遍历Map的所有成员。 forEach接受第二个参数用来绑定this。
var reporter = {
report: function(key, value) {
console.log("Key: %s, Value: %s", key, value);
}
};
map.forEach(function(value, key, map) {
this.report(key, value);
}, reporter);
与其他数据结构的互相转换
- Map和互转数组
let arr2 = [ [{ a: 2 }, "a111"],
[2, "b"]
];
let map = new Map(arr2);
map; // Map(2) { { a: 2 } => 'a111', 2 => 'b' }
[...map]; // [ [ { a: 2 }, 'a111' ], [ 2, 'b' ] ]
- Map和对象互转 前提是map的键名都是字符串
const strObjToMap = (obj) => {
const map = new Map();
for (let l in obj) {
console.log(l);
map.set(l, obj[l]);
}
return map;
};
const strMapToObj = (map) => {
let result = {};
for (let l of map.entries()) {
console.log(l);
result[l[0]] = l[1];
}
return result;
};
let obj1 = { 2: "b", 12: "a111" };
strObjToMap(obj1); // Map(2) { '2' => 'b', '12' => 'a111' }
strMapToObj(map); // { '2': 'b', '12': 'a111' }
- Map和Json互转 Map和Json互转,需要注意json是不是二维数组,map的键名是不是字符串
let json1 = {
a: 1,
b: 2
};
let json2 = [ [1, 2],
[2, 3]
];
let json3 = [1, 2, 3, 4];
const strJsonToMap = (json) => {
if (Array.isArray(json) && json.some((item) => Array.isArray(item))) {
return new Map(json);
}
return strObjToMap(json);
};
const strMapToJson = (map) => {
if ([...map.keys()].every((item) => typeof item === "string")) {
return strMapToObj(map);
}
return [...map];
};
strJsonToMap(json1); // Map(2) { 'a' => 1, 'b' => 2 }
strJsonToMap(json2); // Map(2) { 1 => 2, 2 => 3 }
strJsonToMap(json3); // Map(4) { '0' => 1, '1' => 2, '2' => 3, '3' => 4 }
strMapToJson(new Map().set(json1, "a")); // [ [ { a: 1, b: 2 }, 'a' ] ]
strMapToJson(strJsonToMap(json1)); // { a: 1, b: 2 }
WeakMap
WeakMap结构与Map结构基本类似,唯一的区别是它只接受对象作为键名(null除外),不接受其他类型的值作为键名,而且键名所指向的对象不计入垃圾回收机制。WeakMap的设计目的在于,键名是对象的弱引用(垃圾回收机制不将该引用考虑在内),所以其所对应的对象可能会被自动回收。WeakMap的专用场合就是,它的键所对应的对象,可能会在将来消失。
var wm = new WeakMap();
var element = document.querySelector(".element");
wm.set(element, "Original");
wm.get(element) // "Original"
element.parentNode.removeChild(element);
element = null;
wm.get(element) // undefined
Proxy 和 Reflect
Proxy 概述
Proxy拦截器用于修改某些操作的默认行为
var obj2 = new Proxy(
{},
{
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
}
);
obj2.key = 1; // setting key!
obj2.key; // getting key!
Proxy 支持的拦截操作一览。
- get(target, propKey, receiver) 读取拦截,拦截对象属性的读取,比如
proxy.foo和proxy['foo']。最后一个参数receiver是一个对象。 - set(target, propKey, value, receiver) 赋值拦截,拦截对象属性的设置,比如
proxy.foo = v或proxy['foo'] = v,返回一个布尔值。 - has(target, propKey) 判断是否拥有拦截,拦截
propKey in proxy的操作,以及对象的hasOwnProperty方法,返回一个布尔值。 - deleteProperty(target, propKey) 删除拦截,拦截
delete proxy[propKey]的操作,返回一个布尔值。 - ownKeys(target) 读取属性数组拦截,拦截
Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一个数组。该方法返回对象所有自身的属性,而Object.keys()仅返回对象可遍历的属性。 - getOwnPropertyDescriptor(target, propKey) 拦截
Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。 - defineProperty(target, propKey, propDesc) 拦截
Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。 - preventExtensions(target) 拦截
Object.preventExtensions(proxy),返回一个布尔值。 - getPrototypeOf(target) 拦截
Object.getPrototypeOf(proxy),返回一个对象。 - isExtensible(target) 拦截
Object.isExtensible(proxy),返回一个布尔值。 - setPrototypeOf(target, proto) 拦截
Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。 - apply(target, object, args) 拦截 Proxy 实例作为函数调用的操作,比如
proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。 - construct(target, args) 拦截 Proxy 实例作为构造函数调用的操作,比如
new proxy(...args)。
Iterator和for...of循环
Iterator的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。
Generator 函数
Generator函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
yield语句
遍历器对象的next方法的运行逻辑如下。
(1)遇到yield语句,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。
(2)下一次调用next方法时,再继续往下执行,直到遇到下一个yield语句。
(3)如果没有再遇到新的yield语句,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。
(4)如果该函数没有return语句,则返回的对象的value属性值为undefined。
yield语句如果用在一个表达式之中,必须放在圆括号里面。
es6转码es5
1、安装脚手架
npm install --global babel-cli
2、配置配置文件.babelrc
.babelrc基本格式为
{
"presets": [],
"plugins": []
}
添加相关规则如
{
"presets": [
"es2015",
"react",
"stage-2"
],
"plugins": []
}
预设规则集:
// ES2015转码规则
$ npm install --save-dev babel-preset-es2015
// react转码规则
$ npm install --save-dev babel-preset-react
// ES7不同阶段语法提案的转码规则(共有4个阶段),选装一个
$ npm install --save-dev babel-preset-stage-0
$ npm install --save-dev babel-preset-stage-1
$ npm install --save-dev babel-preset-stage-2
$ npm install --save-dev babel-preset-stage-3
3、使用命令行转码babel-cli
基本用法
// 转码结果输出到标准输出
$ babel example.js
// 转码结果写入一个文件
// --out-file 或 -o 参数指定输出文件
$ babel example.js --out-file compiled.js
// 或者
$ babel example.js -o compiled.js
// 整个目录转码
// --out-dir 或 -d 参数指定输出目录
$ babel src --out-dir lib
// 或者
$ babel src -d lib
// -s 参数生成source map文件
$ babel src -d lib -s