事关我对于JavaScript高级的一些理解

415 阅读8分钟

Javascript

写在前面:这一篇是我总结的关于JavaScript高级的一些知识,包括但不限于ES6范围内,而且也基本都是面试用得上的知识

Promise和async await

Promise定义

  1. 三种状态,不可逆,两个参数,成功回调,失败回调.then也是这两个参数
  2. .then不传值,则为undefined,传普通数据,则为下一个函数的参数,传promise对象,则把异步结果作为参数传递
  3. 如果不设置失败回调,错误无法抛出,一般在最后设置一个.catch用来错误捕获 , 不会因此阻塞代码执行.
  4. Promise.resolve 返回一个成功Promise,reject相反
  5. Promise.all(),等待所有结束,有一个失败,就算失败
  6. Promise.race(),等待最快的返回结果,最快的是什么,race就是什么
  7. Promise.finally(),不管结果如何都会执行

Promise的理解

优点:

异步代码同步化解决方案,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数,顺带解决了回调地狱的代码.(真正解决要靠async和await,他是Promise和Generator函数的语法糖,async函数包裹异步请求函数得到返回值操作才能跳出回调地狱.)

缺点:

首先它状态不能被改变,其次如果处于pending状态,无法得知它是刚开始还是要结束,还有是如果没有回调函数,promise内部抛出的错误,不会反应到外部.

Promise/A+规范

  1. promise表示异步操作的最终结果(状态) , 是一个包含了promise规范的then方法的对象或者函数.
  2. 必须要有个值响应当前promise的状态 , pengding(等待) , fulfilled(成功) , rejected(失败)
  3. then方法需要可以被链式调用 , 因此需要返回一个promise对象
  4. exception, 表示抛出的错误.
  5. reason , 表示被拒绝的原因.

执行上下文,执行上下文栈和作用域

执行上下文

js代码预编译 , var变量提升,函数声明以及this赋值.

  1. 声明时确定自由变量的作用域
  2. 每次函数调用都会有新的执行上下文环境,因为函数相同,参数不同

执行上下文栈

活跃的执行上下文只能有一个 , 多层嵌套形成先进后出的栈.

自由变量

不在当前作用域声明却被调用的变量叫自由变量 , 取自由变量的值需要在声明当前函数的作用域去找

作用域

不同作用域之间的同名变量不会冲突 , 只有函数能创建作用域 , 作用域在函数创建时确定 , 函数内变量的值在代码执行时才确定.不同作用域内可以有多个执行上下文(同一函数,不同参数调用) , 多个执行上下文同一时间只能执行一个,形成执行上下文栈 ,

作用域链

最大的作用域是全局作用域 , 当前作用域没有就跨到更大的作用域找,一直到全局作用域,这条路线被称为作用域链. } 闭包 一个作用域访问另外一个作用域中的变量,并且不会随着函数执行完毕而回收.

浅拷贝和深拷贝

浅拷贝

只会复制第一层的属性(变量),无法拷贝方法(函数),只能拷贝方法地址值, 通过hasOwnProperty方法遍历判断属性是否存在实现浅拷贝 Object.assign()方法也可以实现浅拷贝

深拷贝

  • 通过递归遍历,在碰到有深层对象的时候继续遍历直到没有子对象为止.
  • 通过递归遍历的方式以及先转Json字符串,赋值后再转Json对象的方式实现深拷贝.
  • 通过扩展字符串实现深拷贝
  • Json方式的缺点:拷贝不了Date数据,正则对象,Error对象,undefined等等

事件循环

宏任务

tasks,包括定时器,循环器,I/O,以及script;

微任务

jobs,包括promise的.then,观察者(object.observe) node里面的p rocess.nexttick;

js只能单线程执行代码

  1. 同步代码优先执行,碰到异步请求加入消息队列,分为宏任务队列和微任务队列。
  2. 同步代码全部执行完成,开始执行消息队列的请求,优先级:微任务>宏任务, 先执行完所有微任务,如果微任务执行过程中又有新的微任务或者宏任务,依旧分别加入消息队列,如果第一遍微任务执行完毕后没有新的微任务加入则开始执行宏任务,否则继续执行微任务,一直循环执行这个操作,叫做事件循环,直到消息队列中不存在微任务和宏任务。
  3. 同步代码和微任务执行完成,开始执行宏任务,如果宏任务中包含微任务则下次循环会再优先执行微任务,然后再执行宏任务。

common.js和ES6模块化

一 . common.js是模块化 , 每个模块都是单独的作用域

利用require方法读取module.export导出的对象.但因为require是同步的 , script标签天生异步的 , 所以需要处理方案

AMD方案:

异步模块定义 , 借助require.js解决了多个js文件依赖的关系,以及js加载时浏览器会停止运行两个问题.(异步加载 ,解决浏览器卡顿 , 指定回调函数 , 一号位没加载完不会加载二号位,解决多文件依赖)

CMD方案:

通用模块定义 , 借助sea.js , 推崇一个模块一个文件.

关系和区别

都是解决的同样的问题,只是方法略有不同,AMD推崇依赖前置,定义的时候就要声明 , CMD推崇就近依赖,用到的时候才加载 AMD用户体验好,因为没有延迟,依赖模块提前执行了,CMD性能好,因为只有用户需要的时候才执行

二. ES6 Modules

是js自带的语法,是声明式的代码集合(集合里面保存可以导出的变量以及导出数据的内存地址)

三. 关系和区别

写法区分:

//导入
common.js:let a = require()
ES6      :import {a} from ''./index.js

//导出 
common.js: module.export
ES6      : export defaultexport const  mode = {};
  • ES6是在代码正式运行之前(编译阶段)执行, 而CommonJS必须在运行时执行
  • es6一般在浏览器环境 , common.js一般在node环境

原型和原型链

  1. 所有的实例对象,都有一个隐式原型__proto__,构成原型链(尝试访问一个属性或方法,如果不存在,访问其构造函数,逐级查找,直到对象原型.)
  2. 所有的构造函数都有一个显式原型prototype. 同时显式原型有一个constructor(构造器)指回其构造函数.
  3. 实例对象的_proto_指向其构造函数的prototype
  4. Object.prototype = null (原型链最深处,历史遗留问题)
  5. Function的_proto_和prototype都指向Function.prototype(function的原型对象)

面向对象的理解

面向对象就是把所有的事物都看作是对象 , 每个对象的出现都只为解决某个单一需求 , 对象拥有三大特点: 不跟其他对象有所关联. 每个对象都相对独立叫封装 , 实例对象可以调用原型对象的方法叫继承 , 对象的方法可以多种调用方式 , 不同的方法实现不同的功能叫多态.

typeof,instanceof和toString

typeof(类型判断)无法检测复杂类型(array,object,null) , 查出来都是object,

console.log(typeof(a))	//number(返回类型)

instanceof(实例),判断该对象是谁的实例,是否在其原型上(只能判断引用类型)

obj1 instanceof obj2  //true or false(判断是否属于该类型,返回布尔值)

Object.prototype.toString.call() Object对象和它的原型链上各自有一个toString()方法,第一个返回的是一个函数,第二个返回的是值类型,Array,Function,Date继承的是Object.toString() , 是一个函数 , 判断值得用object.prototype的toString,是一个值类型.

柯里化函数

柯里化函数是:是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。(改变函数传参方式)

// 普通的add函数
function add(x, y) {
    return x + y
}

// 柯里化后
function curryingAdd(x) {
    return function (y) {
        return x + y
    }
}

add(1, 2)           // 3
curryingAdd(1)(2)   // 3

扁平化数据

扁平化概念的核心意义是:去除冗余、厚重和繁杂的装饰效果。其实就是多维数组降维成一维数组,嵌套对象解耦成一级对象(只有一级没有子级对象).

扁平化方法:

1.flat()
    let arr2 = [1, 2, [3, 4, [5, 6]]];
    arr2.flat(1); // [1, 2, 3, 4, [5, 6]]
2.扩展字符串
    let arr = [[1, 2, [3, 4], 5], [6, 7, 8], [[9, 10], 11]]
        function flat(arr) {
          while (arr.some(item => Array.isArray(item))) {
            arr = [].concat(...arr);
          }
          return arr;
        }
    console.log(flat(arr)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
3.reduce()
    let arr = [[1, 2, [3, 4], 5], [6, 7, 8], [[9, 10], 11]];
        function flat(arr) {
          return arr.reduce(function (prev, cur) {
            return prev.concat(Array.isArray(cur) ? flat(cur) : cur);
          }, [])
        }
    console.log(flat(arr)); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
 //数组扁平化和对象扁平化大同小异

AST树形结构

AST树形结构,就是把js代码按照特定的规则,变成特殊对象,以至于在更改js逻辑的时候,其实就是修改了AST对象的属性值,然后再变成js源码,转换规则可以自定义,也可以使用社区规范

End