有的内容是三四年前写的。
Module
chrome 已经支持 module,需要注意 script 标签需要加上 type="module",
<script type="module" src="2.js"></script>
export
使用示例:
export var firstName = 'Michael';
export function multiply(x, y) {
return x * y;
};
export { last, year };
错误写法:
var m = 1;
export m;
import
示例代码:
import {firstName, lastName, year} from './profile.js';
import 'lodash';
只是将其内部的代码执行一遍,上面的例子也会执行module内部的代码。
module 内部定义的变量不会暴露出来。
模块整体加载:import * as circle from './circle';
export default
使用:
export default function() {
console.log('lala')
}
import fn from './1.js'
一个module中只能有一个 export default。
如果将module整体加载,export default 的内容也是其中一项,key 是 default
和直接export不同之处:
正确:
var a = 1
export default a
错误:
export default var a = 1;
总结:export 后面需要声明性质的东西,export default 后面需要具体的值
export 与 import 的复合写法
import { foo, bar } from 'my_module';
export { foo, bar };
可以写成:
export { foo, bar } from 'my_module';
注意,这样写以后,foo 和 bar 不能在当前的 module 使用
其它例子:
export { foo as myFoo } from 'my_module';
export * from 'my_module';
export { default } from 'foo';
import()
待补充
一些提示
import 引入的变量都是常量。 如果一个HTML文件引用了两个JS文件,这两个JS文件都引用了同一个module,前者对引用到的变量的修改会影响到后者读取到的内容(如果引用的变量是对象,可以修改其属性)。
函数
函数参数的默认值是『惰性求值』的
看下面这个例子:
function foo({x, y = 5} = {}) {
console.log(x, y);
}
foo() // undefined 5
函数参数的默认值是{ },如果函数调用提供了参数,则变量x和y通过解构赋值生成,解构赋值中y是有默认值的
错误的写法:
// 报错
function f(a, ...b, c) {
// ...
}
因为rest参数只能是最后一个参数
箭头函数
特点:
没有 this,所以也不能作为构造函数,不能用call()、bind()等
没有 arguments
不能使用 yield 命令
箭头函数中的this对象,是定义时所在的对象,而不是使用时所在的对象,所以也是固定不变的
看下面的例子:
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
数组
扩展运算符
将数组转为逗号分隔的参数序列
可以将有 iterator 接口的数据结构转为数组,如 Arguments、NodeList 等
主要用于函数调用,可以替代函数的 apply 方法
运用:
求一个数组的最大元素:
// ES5 的写法
Math.max.apply(null, [14, 3, 77])
// ES6 的写法
Math.max(...[14, 3, 77])
把一个数组的元素 push 进另一个数组
// ES5的 写法
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
// ES6 的写法
let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);
复制数组:
// ES5
const a2 = a1.concat();
// ES6
const a2 = [...a1];
合并数组:
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5 的合并数组
arr1.concat(arr2, arr3);
// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
把字符串转为数组:
[...'hello']
扩展运算内部调用的是Iterator接口,因此只要具有Iterator接口的对象,都可以使用扩展运算符转为数组,如 Set / Map / Generator函数返回的结果等
Array.from()
可以将两类对象转为数组:array-like 和 iterable
可以接受第二个参数,作用类似 map:
Array.from([1, 2, 3], x => x * x)
// [1, 4, 9]
// 等同于
Array.from(arrayLike).map(x => x * x);
其它
fill() 使用给定值,填充一个数组
new Array(3).fill(7)
// [7, 7, 7]
entries(),keys() 和 values() 返回的是 Iterator 对象,可以使用 for...of 遍历 flat() 可以将嵌套的数组拉平,参数指定想要拉平的层数
对象
对象合并:Object.assign()
克隆对象:Object.assign({}, origin)
属性的遍历
for...in 返回自身和继承的 enumerable 属性
Object.keys() 返回自身的 enumerable 属性
Object.getOwnPropertyNames() 返回自身的 enumerable 和 innumerable 属性
Object.getOwnPropertySymbols() 返回自身的所有 Symbol 属性
Reflect.ownKeys() 返回自身的所有键名
Object.create(),Object.getPrototypeOf(),Object.setPrototypeOf()
尽量不要直接操作__proto__,而是使用
Object.setPrototypeOf() Object.getPrototypeOf() Object.create()代替
使用示例:
// es5 的写法
obj.__proto__ = someOtherObj;
// es6 的写法
var obj = Object.create(someOtherObj);
// 格式
Object.setPrototypeOf(object, prototype)
// 用法
const o = Object.setPrototypeOf({}, null);
Object.getPrototypeOf(obj);
super关键字
指向当前对象(定义时所在对象)的__proto__,只能用在对象的方法之中(只能用简写的对象方法)
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find() {
return super.foo;
}
};
Object.setPrototypeOf(obj, proto);
obj.find() // "hello"
Object.keys(),Object.values(),Object.entries()
可以和 for...of 配合使用,用于遍历对象
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
Object.keys(obj) 返回由键名组成的数组
Object.values(obj) 返回由键值组成的数组
Object.entries() 返回由键值对组成的数组
使用 Object.entries() 将对象转为Map结构:
const obj = { foo: 'bar', baz: 42 };
const map = new Map(Object.entries(obj));
map // Map { foo: "bar", baz: 42 }
对象的扩展运算符
const [a, ...b] = [1, 2, 3];
a // 1
b // [2, 3]
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
合并两个对象:
let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);
Symbol
是一种新的原始数据类型
可以作为对象的 key,保证属性名不会发生冲突
创建 Symbol:
let s = Symbol();
Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
let s1 = Symbol('foo');
s1 // Symbol(foo)
s1.toString() // "Symbol(foo)"
Symbol 类型还可以用于定义一组常量,保证这组常量的值都是不相等的
实例:消除魔术字符串
const shapeType = {
triangle: Symbol()
};
function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = .5 * options.width * options.height;
break;
}
return area;
}
getArea(shapeType.triangle, { width: 100, height: 100 });
属性名的遍历
Symbol 作为属性名,该属性不会出现在 for...in、for...of 循环中,也不会被 Object.keys() 等方法返回 Object.getOwnPropertySymbols 方法,可以获取指定对象的所有 Symbol 属性名
Symbol.for(),Symbol.keyFor()
Symbol.for() 接受一个字符串作为参数,然后搜索有没有以该参数作为名称的 Symbol 值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true
Symbol.keyFor() 方法返回一个已登记的 Symbol 类型值的key。
let s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
let s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
内置的 Symbol 值
Symbol.hasInstance
指向一个内部方法。当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
Symbol.isConcatSpreadable
Symbol.species
Symbol.match
Symbol.replace
Symbol.search
Symbol.split
Symbol.iterator
Symbol.toPrimitive
Symbol.toStringTag
Symbol.unscopables