JS
1 var let const 区别
变量提升和暂时性死区
console.log(a); // undefined
var a = 10;
console.log(b); // ReferenceError
let b = 20;
console.log(c); // ReferenceError
const c = 30;
作用域
var // 全局作用域 函数作用域
let // 块级作用域
const // 块级作用域
重复声明
var a = 10;
var a = 20; // 20
let b = 10;
let b = 20; // SyntaxError
const c = 10;
const c = 20; // SyntaxError
2 es6 数组的扩展
将其他数据结构转成真正的数组
let set = new Set([1, 2, 2, 3]);
let arr = [...set]; // [1, 2, 3]
Array.from()
将类数组和可遍历对象转成数组
let arrayLike = {
'0': 1,
'1': 2,
'2': 3,
length: 3,
};
Array.from(arrayLike, x => x * x); // [1, 4, 9]
Array.prototype.flat()
[1, [2, [3, 4], 5], 6].flat() // [1, 2, [3, 4], 5, 6]
[1, [2, [3, 4], 5], 6].flat(2) // [1, 2, 3, 4, 5, 6]
Array.prototype.flatMap()
相当于先map后flat
[1, 2, 3].flatMap(x => [x, x * 2]) // [1, 2, 2, 4, 3, 6]
3 es6 对象的扩展
Object.setPrototypeOf()
和super
const a = {name: 'wqd'};
const b = {
getName() {
return super.name;
}
};
Object.setPrototypeOf(b, a); // 设置a为b的原型对象
b.getName(); // 'wqd'
对象属性的遍历
方法名 | 适用范围 |
---|---|
for in | 自身和继承的可枚举属性(非Symbol) |
Object.keys() | 自身的可枚举属性(非Symbol) |
Object.getOwnPropertyNames() | 自身的(含不可枚举)(非Symbol) |
Object.getOwnPropertySymbols() | 自身Symbol |
Reflect.ownKeys() | 自身(含Symbol)(含不可枚举) |
Object.is()
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
4 Promise
三种状态
pending
fulfilled
rejected
方法
Promise.all()
Promise.race()
Promise.allSettled()
Promise.resolve()
Promise.reject()
5 Generator
next
方法的参数会作为上一个yield
的返回值
function* foo(x) {
var y = 2 * (yield(x + 1));
var z = yield(y / 3);
return x + y + z;
}
var x = foo(5);
x.next(); // {value: 6, done: false}
x.next(12); // {value: 8, done: false}
x.next(13); // {value: 42, done: true}
通过添加
Generator
函数使普通对象可遍历
function* f(obj) {
let x = Reflect.ownKeys(obj);
for (let i of x) {
yield [i, obj[i]];
}
}
const obj = {name: 'wqd', year: 1996};
for (let [key, value] of f(obj)) {
console.log(`${key}: ${value}`);
}
// name: wqd
// year: 1996
6 异步解决方案
方法 | 分析 |
---|---|
回调函数 | 回调地狱 |
Promise | 链式调用但代码不简洁语义化不强 |
Generator | 将异步代码以同步的形式进行编写 |
async/await | 简洁语义化强 |
7 Proxy 代理
get()
function createArray(...elements) {
let handler = {
get(target, propKey, receiver) {
let index = Number(propKey);
if (index < 0) {
propKey = String(target.length + index);
}
return Reflect.get(target, propKey, receiver);
}
};
let target = [];
target.push(...elements);
return new Proxy(target, handler);
}
let arr = createArray('a', 'b', 'c');
console.log(arr[-1]); // 'c'
set()
let validator = {
set(obj, prop, value) {
if (prop === 'age') {
if (!Number.isInteger(value)) {
throw new TypeError('不是数字');
}
if (value > 200) {
throw new RangeError('超出范围');
}
}
obj[prop] = value;
}
};
let person = new Proxy({}, validator);
person.age = 100;
console.log(person.age); // 100
person.age = 'wqd'; // TypeError
person.age = 300; // RangeError
8 Module
导入导出复合写法
export { foo, bar } from 'module'
// 等同于
import { foo, bar } from 'module'
export { foo, bar }
9 数组方法
修改原数组 | 不修改原数组 |
---|---|
push unshift splice pop shift
|
concat slice some every forEach filter map
|
10 深浅拷贝
浅拷贝
function shallowClone(obj) {
const newObj = {};
for(let prop in obj) {
if(obj.hasOwnProperty(prop)) {
newObj[prop] = obj[prop];
}
}
return newObj;
}
深拷贝
JSON.stringify()
会忽略undefined
Symbol
function
const obj = {
a: "A",
b: undefined,
c: function() {},
d: Symbol("A"),
};
const newObj = JSON.parse(JSON.stringify(obj));
console.log(newObj); // {a: 'A'}
11 原型和原型链
function Person(name) {
this.name = name;
this.age = 18;
this.sayName = function() {
console.log(this.name);
}
}
const person = new Person("person");
// true
person.__proto__ === Person.prototype
Person.__proto__ === Function.prototype
Person.prototype.__proto__ === Object.prototype
Object.__proto__ === Function.prototype
Object.prototype.__proto__ === null
Function.__proto__ === Function.prototype
12 实现继承的方式
原型链继承
function Parent() {
this.name = "a";
this.arr = [1, 2, 3];
}
function Child() {
this.type = "b";
}
Child.prototype = new Parent();
// 潜在问题
let a = new Child();
let b = new Child();
a.arr.push(4);
console.log(a.arr, b.arr); // 同为 [1, 2, 3, 4]
构造函数继承 只继承父类的实例属性和方法
function Parent() {
this.name = "a";
}
Parent.prototype.getName = function () {
return this.name;
}
function Child() {
Parent.call(this);
this.type = "b";
}
let child = new Child();
console.log(child); // {name: 'a', type: 'b'}
console.log(child.getName()); // TypeError
组合继承 重复执行会有额外性能开销
function Parent() {
this.name = "a";
this.arr = [1, 2, 3];
}
Parent.prototype.getName = function () {
return this.name;
}
function Child() {
Parent.call(this);
this.type = "b";
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
let a = new Child();
let b = new Child();
a.arr.push(4);
console.log(a.arr, b.arr); // [1, 2, 3, 4] [1, 2, 3]
console.log(a.getName(), b.getName()); // "a" "a"
原型式继承 浅拷贝
let parent = {
name: "a",
arr: [1, 2, 3],
getName: function () {
return this.name;
}
};
let person = Object.create(parent);
寄生式继承
let parent = {
name: "a",
arr: [1, 2, 3],
getName: function () {
return this.name;
}
};
function clone(obj) {
let clone = Object.create(obj);
clone.getArr = function () {
return this.arr;
};
return clone;
}
let person = clone(parent);
寄生组合式继承
function clone(parent, child) {
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
}
function Parent() {
this.name = "a";
this.arr = [1, 2, 3];
}
Parent.prototype.getName = function () {
return this.name;
}
function Child() {
Parent.call(this);
this.type = "b";
}
clone(Parent, Child);
Child.prototype.getType = function () {
return this.type;
}
let person = new Child();
13 this绑定规则 优先级从高到低
new绑定 显式绑定 隐式绑定 默认绑定