编程思想:面向过程、面向对象
上下文
分类:全局上下文、局部上下文
全局上下文是window/global
对象,每一次函数开始执行时创建函数上下文对象,该对象入栈、执行完毕时该函数上下文对象出栈
上下文对象在创建时,会在内部创建两个对象:词法环境对象和变量环境对象
1.词法环境对象
let cosnt 函数 形参(arguments)
变量环境对象
var声明的变量
作用域与作用域链
分为:全局作用域、局部作用域(函数作用域、块级作用域)
全局作用域:全局上下文window/global
产生的作用范围
函数作用域:函数内部声明的变量作用域的范围只在函数内部有效
块级作用域:es6 新增,在代码块中let、const声明的变量才能使用该变量
作用域链:程序先查找当前作用域,如果没有,则查找外部的作用域,直到全局作用域。
从执行栈的的角度解释作用域链:程序从栈顶开始查找,如果没有,则通过指针向下查找,指向的那个当前函数的上下文对象,直到栈底的全局上下文对象
构造器
class类
单继承、super、static、__proto__、prototype
//
class Student extends Person{
static count=5;//静态属性、静态函数
//constructor内是实例对象自身的属性方法,外面为原型中的方法
constructor(name,age) {
super(name);
this.age=age;
}
sayHi() {
alert('hello');
}
}
静态属性、函数
- 静态属性和静态函数会一直存在于内存中(只存一份),永远不会被回收
- 静态函数可以通过类名访问
- 实例对象可以访问普通函数,不能访问静态函数
- 静态函数中的this关键字指向的当前类
- 静态属性、方法被用于实现属于整个类的功能。它与具体的类实例无关
原型及原型链
隐式原型:每个对象的__proto__
都指向对象的原型
显式原型:每个构造函数或类的prototype
都指向原型对象
原型对象的constructor
都指向构造器或类函数
原型:每一个实例对象都有显示原型和隐式原型,它的__proto__
都指向对象的原型,构造函数或类的prototype
都指向原型对象,原型对象的constructor
都指向构造器或类函数。实例对象的共有方法都存在原型中。
原型链:一个对象在使用方法或者属性的时候,首先会在自身的寻找,如果没有找到就到原型上面去寻找,依次向上查找直到到object为止,如果还是未找到返回为undefined—这样一层一层向上查找就会形成一个链式结构,我们称为原型链。
类的继承本身就是原型链的继承
原型对象有
- 构造器(constructor),指向当前函数/类本身
- 自定义的原型方法
- 它自己的原型对象
this指向问题
- 普通函数:this指向window,严格模式指向undefined
- 对象的方法:调用时指向该对象
- 构造函数或类:指向构造函数的实例对象
- 箭头函数:指向箭头函数对应的上下文
- 立即执行函数:指向window对象
- 绑定的事件:指向事件的对象
- 定时器:指向window
闭包
函数之中嵌套函数,里层函数可以使用外层函数的变量
特点:
-
内部函数能够使用外部函数的局部变量
-
外部函数的局部变量会一直保留在内存中,并且不会销毁
优点:延长了变量的生命周期
缺点:造成了一个永远不会销毁的作用域,参数和变量不会被回收,会导致内存泄漏
垃圾回收
- 全局变量不可回收
- 被应用的局部变量不可回收
- 处于可达状态下不可回收
递归
特点:
- 在运行过程中,自身调用自身
- 递归函数必须接收参数(我要递归谁)
- 至少应该有一个结束条件
ES6
1 模板字符串
2 class
3 箭头函数
4 let、const
5 严格模式
6 扩展运算符
7 解构
8 Object.keys
9 for - of
10 set和map
11 rest参数(可变参数)
12 异常处理
var
1 能够重复定义
2 预编译/预解析(变量的提升)
3 只有全局作用域和局部作用域
4 全局下定义后会成为window的属性
let
1 在同一个区域中不能重复定义
2 没有变量提升
3 有块级作用域,有暂存性死区
const
1 声明既要赋值 ,其他和let一样
2 数据地址不可变,常量大写
错误处理
try...catch
结构允许我们处理执行过程中出现的 error。从字面上看,它允许“尝试”运行代码并“捕获”其中可能发生的错误。捕获同步代码,捕获异常、不会终止程序执行
promise
三种状态:pending、fullfilled、rejected
then \catch\finally
Promise.all 一个异常直接error,未执行的Promise 停止
Promise.allSettled 不管成功还是失败,在then中返回
Promise.race 返回第一个成功的promise
Promise.any 返回第一个promise 无论是否成功失败
成功都返回存放它们结果的数组
async/await
async
有两个作用:
- 让这个函数总是返回一个 promise,代表该函数为异步函数 。
- 允许在该函数内使用
await
,await 后面需要搭配promise对象/异步请求,表明会等待异步请求的结果。 - await 只能等待正确的结果(try-catch来捕获异常(接受reject的值))
微任务、宏任务
宏任务:setTimeout、setInterval、IO等,执行方式是将任务通过从任务队列中拿出执行,再拿出执行的在渲染的方式
微任务:promise》then,process.nextTick(node),asycn.await等等先将异步代码执行完毕,在进行渲染
深拷贝、浅拷贝
浅拷贝是对地址的引用、深拷贝是将其本身以及内部所有的引用数据类型拷贝一个新的对象(新地址)。
JSON深拷贝弊端
1 如果对象中的属性带有date,则会转成字符串
2 如果 obj 里有 RegExp (正则表达式的缩写)、Error 对象,则序列化的结果将只得到空对象
3 如果 obj 里有函数(function),undefined,Symbol 则序列化的结果会把 function 或 undefined 丢失
new关键字
\1. 创建一个空对象
\2. 设置原型链
\3. 让实例化对象中的this指向对象,并执行函数体
\4. 判断实例化对象的返回值类型
function newFn(fn, ...rest) {
let obj = {};
obj.__proto__ = fn.prototype;
let result = fn.apply(obj, rest);
if (result === null) {
return obj;
}
return typeof result === 'object' ? result : obj;
}
异步编程的实现方式
- 回调函数
- 事件监听
- 发布订阅模式
- promise
- generator
- async、await
函数柯里化
是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数。并且返回接受余下的参数而且返回结果的新函数的技术。
应用
-
参数复用
返回一个新的函数时,将某一个参数一直复用,调用方便
-
延迟运行
js中经常使用的bind,实现的机制就是Currying.
// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
function add() {
// 第一次执行时,定义一个数组专门用来存储所有的参数,arguments是伪数组
var _args = Array.prototype.slice.call(arguments);
// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
var _adder = function() {
_args.push(...arguments);
return _adder;
};
// 利用toString隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
_adder.toString = function () {
return _args.reduce(function (a, b) {
return a + b;
});
}
return _adder;
}
add(1)(2)(3) // 6
add(1, 2, 3)(4) // 10
add(1)(2)(3)(4)(5) // 15
add(2, 6)(1) // 9