箭头函数
与普通函数区别
- 箭头函数 this 不可修改(call、apply、bind),在定义时决定:指向外层第一个普通函数。
- 不能被 new
- 没有 prototype
- 没有 arguments
new 一个箭头函数
- 会报错,提示: function is not a constructor;
- babel 编译时,会把 this 转成 (void 0);
哪些不能用箭头函数
- arguments
- yield
- 构造函数的原型方法上
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const Person = function (age, name) { this.age = age; this.name = name;
const obj = { 0: 18, 1: "luyi", 2: "teacher", 3: "esnext" }; console.log(arguments.callee); obj.length = 4; console.log(Array.prototype.slice.call(obj, 2)); };
const fibonacci = function (num) { if (num <= 2) return 1; return arguments.callee.caller(num - 1) + arguments.callee.caller(num - 2); };
console.log(fibonacci(4));
|
模板字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| const consoleList = function (student, teacher) { console.log(`hello ${student}, I am ${teacher}, nice 2 meet U`); };
const consoleString = function (stringTemplate, ...restVal) { console.log( stringTemplate.reduce( (total, item, index) => total + item + (restVal[index] || ""), "" ) ); };
const stu = "my students"; const tea = "luyi";
consoleString`hello ${stu}, I am ${tea}, nice 2 meet U`;
|
数组和对象
数组和对象的细节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
const funcGenerator = (num) => Array.from(new Array(num)).map((item) => (params) => console.log(params)); const funcGenerator = (num) => new Array(num).fill(0).map((item) => (params) => console.log(params));
console.log(NaN === NaN); console.log(Object.is(NaN, NaN));
console.log([NaN].indexOf(NaN)); console.log([NaN].includes(NaN));
|
Object.assign
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
let dist = { foo: "foo" }; let bar = { bar: { bar: "bar" } }; let baz = { baz: "baz" };
const res = Object.assign(dist, bar, baz);
bar.bar.bar = "newBar"; baz.baz = "newBaz";
console.log(res);
console.log(res === dist);
|
get / set
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Person { constructor() {} _age = ""; get age() { console.log(`actually I am ${this._age} years old~`); return "17"; }
set age(val) { console.log(" It is useless to set my age, I am 17!"); this._age = val; } }
|
Proxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const luyi = { age: 35, };
const luyiProxy = new Proxy(luyi, { get: function (target, propKey, receiver) { console.log("GET:", target, propKey); return Reflect.get(target, propKey, receiver); }, set: function (target, propKey, value, receiver) { console.log("SET:", target, propKey, value); return Reflect.set(target, propKey, value, receiver); }, });
console.log((luyiProxy.age = 35));
|
断言函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const assert = new Proxy( {}, { set(target, warning, value) { if (!value) { console.error(warning); } }, } );
const teacher = "luyi";
assert["The teacher is Luyi!!!"] = teacher === "yunyin";
|
receiver
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| const luyi = { age: 35, }; const luyiProxy = new Proxy(luyi, { get: function (target, propKey, receiver) { return receiver; }, set: function (target, propKey, value, receiver) { console.log("SET:", target, propKey, value); return Reflect.set(target, propKey, value, receiver); }, });
console.log(luyiProxy.age === luyiProxy);
|
Reflect
- 将 Object 上一些明显属于语言内部的方法,放到 Reflect 对象上,现在 Object 和 Reflect 一同部署;
- 修改某些 Object 方法的返回结果,让其更合理;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const teacher = { age: 18, name: "luyi", };
Reflect.defineProperty(teacher, "lessions", { writable: false, enumerable: false, configurable: false, value: "vue", });
const res = Reflect.defineProperty(teacher, "lessions", { writable: true, enumerable: true, configurable: true, value: ["es6", "esnext"], });
console.log(res);
|
Map、Set、WeakMap、WeakSet
- Weak 表示作为唯一的部分,必须是一个对象;
- Weak 是一个弱引用,不用考虑 GC;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const foos = new WeakSet();
class Foo { constructor() { foos.add(this); } method() { if (!foos.has(this)) { throw new TypeError(" Foo.prototype.method 只能在实例上调用"); } else { console.log("using methods"); } } }
let f = new Foo(); let b = {}; Foo.prototype.method.call(b);
|
迭代器,Iterator
- 迭代器是一个接口,为各种不同的数据提供统一的访问机制。任何数据结构只要部署了
Iterator
接口,就可以完成遍历操作:
- 本质:指针。
- 该 接口主要供
for...of
消费。
for...of
普通原始对象会报错:1. 类数组对象转成数组(…/Array.from/Array.prototype.slice.apply(arguments));2. 如果不是类数组对象,就给对象添加一个[Symbol.iterator]属性,并指向一个迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var obj = { a: 1, b: 2, c: 3, };
obj[Symbol.iterator] = function* () { var keys = Object.keys(this); for (var k of keys) { yield [k, obj[k]]; } };
for (var [k, v] of obj) { console.log(k, v); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
let arr = [1, 2, 3, 4, 5]; let k = arr[Symbol.iterator]();
console.log(k.next()); console.log(k.next()); console.log(k.next()); console.log(k.next()); console.log(k.next()); console.log(k.next());
|
- 原生具备 Iterator 的数据结构有:
Array Map Set String TypedArray arguments NodeList
Object.entries
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
| const obj = { a: 11, b: 22, c: 33 };
console.log(Object.entries(obj)); console.log(Object.keys(obj)); console.log(Object.values(obj));
function entries(obj) { let arr = []; for (let key of Object.keys(obj)) { arr.push([key, obj[key]]); } return arr; }
function* entires(obj) { for (let key of Object.keys(obj)) { yield [key, obj[key]]; } }
const k = entires(obj);
for (let item of k) { console.log(item); }
|
promise.allSettled
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
| function allSettled(array) { return new Promise((resolve, reject) => { if (!(array instanceof Array)) return reject(new Error(" not Array!")); const res = []; let count = 0; array.forEach((func, index) => { Promise.resolve(func) .then( (value) => { res[index] = { status: "fulfilled", value, }; }, (reason) => { res[index] = { status: "rejected", reason, }; } ) .finally(() => { ++count === array.length && resolve(res); }); }); }); }
|
let/const vs var
let/const 和 var 的区别
- var 污染全局
- 块级作用域
- 重复声明
- 暂时性死区(变量提升)
块级作用域
1 2 3 4 5 6 7 8 9 10
| if (true) { var arg1 = "云隐"; } console.log("arg1", arg1);
if (true) { const arg2 = "云隐"; } console.log("arg2", arg2);
|
变量提升
执行上下文
全局执行上下文、函数执行上下文、eval 函数执行上下文。可理解为一个抽象的对象

- Variable object: 变量对象,存储被定义在执行上下文中的变量 (variables) 和函数声明 (function declarations)
- Scope chain: 作用域链,对象列表 (list of objects),检索上下文代码中出现的标识符 (identifiers)
- thisValue: this 指针,上下文对象
理解变量提升
执行上下文的生命周期可以分为三个阶段:创建、执行、释放

var
所有使用 var 声明的变量都会在执行上下文的创建阶段时作为变量对象的属性被创建并初始化,从而保证在执行阶段能通过标识符在变量对象里找到对应变量进行赋值操作等
- 由名称和对应值 (undefined) 组成一个变量对象的属性被创建 (创建并初始化)
- 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性
let
其在执行上下文的创建阶段,只会创建变量而不会被初始化,并且 ES6 规定了其初始化过程是在执行上下文的执行阶段 (即直到它们的定义被执行时才初始化),使用未被初始化的变量将会报错 (ReferenceError)
const
const 与 let 类似,都具有上面提到的 let 的特性,唯一区别就在于 const 声明的是一个只读变量,声明之后不允许改变其值。因此,const 一旦声明必须初始化,否则会报错
- 所谓的不可变不是指变量的值不变,而是保证变量指向的内存地址所保存的数据不允许改动 (即栈内存在的值和地址)
dead zone
在变量初始化前访问该变量会导致 ReferenceError ,因此从进入作用域创建变量,到变量开始可被访问的一段时间 (过程),称为暂存死区(Temporal Dead Zone)
1 2 3 4
| if (true) { console.log(arg1); var arg1 = "云隐"; }
|
let or const
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
| const obj = { teacher: "云隐", leader: "小可", }; obj.leader = "部部";
const arr = ["云隐", "小可"]; arr[0] = "aaaa";
object.freeze(obj);
const obj2 = { teacher: "云隐", leader: "小可", zhuawa: ["黄小杨", "部部"], }; object.freeze(obj2); obj2.zhuawa[0] = "云隐";
function deepFreeze() { Object.freeze(obj); (Object.keys(obj) || []).forEach((key) => { let innerObj = obj[key];
if (typeof innerObj === "object") { deepFreeze(innerObj); } }); }
|
class
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
| function Course(teacher, course) { this.teacher = teacher; this.course = course; }
Course.prototype.getCourse = function () { return `teacher is:${this.teacher}, course: ${this.course}`; };
const course = new Course("云隐", "ES6"); course.getCourse();
class Course { constructor(teacher, course) { this.teacher = teacher; this.course = course; }
getCourse() { return `teacher is:${this.teacher}, course: ${this.course}`; } } const course = new Course("云隐", "ES6"); course.getCourse();
|
class 的类型
1
| console.log(typeOf Course);
|
class 的 prototype
1
| console.log(Course.prototype);
|
class & 函数对象 属性
1
| console.log(course.hasOwnProperty("teacher"));
|
属性定义 构造器 & 顶层定义 两种定义方式
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 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
| class Course { constructor(teacher, course) { this.teacher = teacher; this.course = course; }
getCourse() { return `teacher is:${this.teacher}, course: ${this.course}`; }
get teacher() { return this.teacher; }
set teacher(val) { this.teacher = val; } }
class Course { constructor(teacher, course) { this._teacher = teacher; this.course = course; }
getCourse() { return `teacher is:${this.teacher}, course: ${this.course}`; }
get teacher() { return this._teacher; } }
class Course { constructor(teacher, course) { this._teacher = teacher;
let _course = "es6"; this.getCourse = () => { return _course; }; } }
class Course { #course = "es6"; constructor(teacher, course) { this._teacher = teacher; } get course() { return this.#course; } set course(val) { if (val) { this.#course = val; } } }
class utils { constructor(core) { this._main = core; this._name = "my-utils"; this._id = "zhaowa专有"; }
get name() { return { ...this._main.fullName, ...{ name: `utils is ${this._name}`, }, }; } get id() { return { ...this._main.id, id: this._id, }; } set name(val) { this._name = val; } }
|
静态方法
直接挂载在类上的方法无需实例化获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function Course() { } Course.ring = function () { };
class Course { constructor() { }
static ring() { } }
Course.ring();
|
继承
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
| function Course() { } Course.ring = function () { }; Course.prototype.send = function () { };
function Child() { Course.call(this, "云隐", "ES6"); this.run = function () { }; } Child.prototype = Course.prototype;
class Course { constructor() { } static ring() {} send() {} }
class Child extends Course { constructor() { super("云隐", "ES6"); } run() {} }
|