🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 编译器理论 分词/词法分析 -> 解析 -> 代码生成 ## 作用域 ### 理解作用域 > 作用域:收集并维护一张所有被声明的标识符(变量)的列表,并对当前执行中的代码如何访问这些变量强制实施一组严格的规则。 ### 块作用域 `{ .. }`是为一个块,块作用域维护块中的变量列表,块作用域中的变量只在块中有效,不会影响到外部同名变量。 ### 变量提升 ``` var a=1; 先声明,后赋值。声明是在编译时进行,赋值是在执行时进行。 ``` ### TDZ TDZ 又称暂时性死区,指变量在作用域内已经存在,但必须在`let/const`声明后才可以使用。 ### `var`,`let`,`const`区别 * 使用`let/const`声明的变量在声明前存在临时性死区(TDZ),使用会发生错误 * 与`var`声明的区别是`let/const`拥有块作用域; * 使用 `var` 可能造成不小心定义了同名变量,使用`let`,`const`可以避免,因为`let`,`const`声明后的变量不允许在同一作用域中重新声明; * const声明的变量,其值不可改变; * `let`和`const`全局声明的变量不存在于`window`对象中,这与`var`声明不同; ## 隐式转换 基本上所有类型都可以隐式转换为 Boolean类型。 | 数据类型 | true | false | | --- | --- | --- | | String | 非空字符串 | 空字符串 | | Number | 非0的数值 | 0 、NaN | | Array | 数组不参与比较时 | 参与比较的空数组 | | Object | 所有对象 | | | undefined | 无 | undefined | | null | 无 | null | | NaN | 无 | NaN | ## 严格模式 * 变量必须使用关键词声明,未声明的变量不允许赋值 * 关键词不允许做变量使用 * 变量参数不允许重复定义 ## 运算 ### 一元运算符 **前置操作** `++n`,`--n`。前置操作会在表达式最先执行。 **后置操作** `n++`,`n--`。后置操作会在表达式最后执行。 ### 逻辑运算符 **优先级** `&&`的优先级比`||`高。 ## 模板字面量 使用 \` ...\` 符号包裹的字符串中可以写入引入变量与表达式。 例: ~~~ let name = '特朗普'; console.log(`川建国同志的真名是${name}`); ~~~ ## apply/call/bind > 改变this指针,也可以理解为对象借用方法 call与apply 用于显示的设置函数的上下文,两个方法作用一样都是将对象绑定到this,只是在传递参数上有所不同。apply 用数组传参,call 需要分别传参。 bind()是将函数绑定到某个对象,比如 a.bind(hd) 可以理解为将a函数绑定到hd对象上即 hd.a()。与 call/apply 不同bind不会立即执行;bind 是复制函数行为,会返回新函数。 ## 对象 ### 展开语法 ``` //对象合并 let a = {"name":"天天","sex":1}; let b = {"age":24}; let user = {...a,...b,"address":"北京"}; console.log(user); ``` ### Symbol.toPrimitive `Symbol.toPrimitive` 是一个内置的 Symbol 值,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。 ``` let obj = { num: 1, [Symbol.toPrimitive]: function() { return this.num; } }; console.log(obj+1);//2 ``` ### valueOf/toString ``` let obj = { name: "天天", num: 1, valueOf: function() { console.log("valueOf"); return this.num; }, toString: function() { console.log("toString"); return this.name; } }; console.log(hd + 3); //valueOf 4 console.log(`Hi,${obj}`); //toString Hi,天天 ``` ### 代理拦截`Proxy` ### [Reflect](https://developer.mozilla.org/zh-cn/docs/web/javascript/reference/global_objects/reflect) ### 原型链 定义对象的时候,就会生成一个`__proto__`,这个`__proto__`指向的是这个对象的原型,指向的是这个对象的构造函数的`prototype` ``` function A(){} functionB(){} let a = new A(),b = new B(); A.prototype = b; ``` ``` //对象a通过函数A构造,A即为a的构造函数。 a.constructor === A //true //a的原型指向a的构造函数的prototype a.__proto__ === A.prototype //true ``` 下面是对象a的原型链: `a`-`A.prototype (b)`-`B.prototype`-`Object.prototype`-`null` javascript中万物皆可看成对象,函数是`Function`类的创建的实例。 比如A,它是一个函数,也是一个对象,当我们定义函数A的时候,javascript内部实际执行: ``` let A = new Function(); ``` 同理,`Object`,`Function`等是函数也是对象,是对象就会有原型(`__proto__`),下面是这些的原型链分析: ![原型链分析](https://img.kancloud.cn/f3/17/f3172bba0c41702534384e6295a9e8f4_855x633.png) ### 类 #### 生成实例对象在es5和es6中的区别与关联性 在es5中,通过构造函数生成实例对象 ``` function User(name){ this.name = name; } User.prototype.show = function(){} let user = new User(); ``` 在es6中,通过`class`关键词生成实例对象 ``` class User{ constructor(name) { this.name = name; } show(){} } let user = new User(); ``` 关联点: * es5中的构造方法`User`相当于es6中的类`User`的构造方法`constructor`,构造方法中的`this`为实例化对象,给`this`设置的属性和方法是当前实例化对象的属性和方法。 * es5中定义原型方法`User.prototype.show = function(){}`;es6中类中定义的普通方法即为原型方法; #### 类的继承 ``` class User { show() { console.log("user.show"); } } class Admin extends User { constructor(name) { } info() { this.show(); } } let p = new Admin(); let u = new User(); console.dir(p); ``` `class`继承内部使用原型继承 ![](https://img.kancloud.cn/d5/a5/d5a5f4838495182624cfa61720613aaa_512x489.png) 事实上,类`Admin`继承至类`User`,就是设置`Admin.prototype.__proto__ = User.prototype`。 下面同样能实现继承: ``` class User { show() { console.log("user.show"); } } class Admin { constructor(name) { } info() { this.show(); } } Admin.prototype.__proto__ = User.prototype; let p = new Admin(); let u = new User(); console.dir(p); ``` #### 对象检测 `instanceof`,`isPrototypeOf` ### Promise #### 状态说明 Promise包含`pending`、`fulfilled`、`rejected`三种状态 * `pending`指初始等待状态,初始化`promise`时的状态 * `resolve`指已经解决,将`promise`状态设置为`fulfilled` * `reject`指拒绝处理,将`promise`状态设置为`rejected` #### 要点 ``` const p1 = new Promise((resolve, reject) => { setTimeout(() => { reject("操作失败"); }, 2000); }); const p2 = new Promise((resolve, reject) => { resolve(p1); }).then( msg => { console.log(msg); }, error => { console.log(error);//执行这里,“操作失败” } ); ``` * 如果返回值是一个`promise`,如上,`p2`中`resolve`的参数(执行成功的返回值)是`p1`,将会发生: * `p2`的`promise`状态会变成`p1`的`promise`状态; * `p2`需要等待`p1`执行完成(执行完成指p1的Promise状态发生改变); * `p2`的`then`方法会过继给`p1`; * 包含`then`方法的对象可以当作 promise来使用; * 执行`promise`的`then`方法中的成功和失败回调函数,其结果必然返回一个`promise`对象。可指定返回的`promise`对象,若不指定,则默认返回一个状态为`fulfilled`的`promise`对象。若指定返回对象不是`promise`,则返回一个返回值为该对象的`promise`对象; #### `all` 使用`Promise.all`方法可以同时执行多个并行异步操作 * 任何一个`Promise`执行失败就会调用`catch`方法 * 适用于一次发送多个异步操作 * 参数必须是可迭代类型,如Array/Set * 成功后返回`promise`结果的有序数组 * 非`promise`数据添加到`all`中,它将被处理成`Promise.resolve` #### `allSettled` `allSettled`用于处理多个`promise`,只关注执行完成,不关注是否全部执行成功,`allSettled`状态只会是`fulfilled`。 #### `race` 使用`Promise.race()`处理容错异步,哪个Promise先返回用哪个。 * 以最快返回的promise为准 * 如果最快返加的状态为`rejected`那整个`promise`为`rejected`执行cache * 如果参数不是promise,它将被处理成`Promise.resolve` #### `async/await` * `async/await`本质还是promise,只是更简洁的语法糖书写 * `async/await`使用更清晰的promise来替换 promise.then/catch 的方式 * 在函数前加上`async`,函数将返回`promise` * 使用`await`关键词后会等待`promise`完成,并返回结果