ES5继承的演变
es6中的class语法与es5的继承机制完全不同,es6是通过extend语法中contructor调用父类的构造函数super完成新建父类的this对象,得到与父类同样的实例属性和方法,然后再对其进行加工,完成子类的继承。
es5中是通过先生成子类的构造函数,再通过call调用父类的构造函数,以及原型指向的方式实现继承,首先生成一个空对象,再进行.call继承,原型继承,最终将这个对象返回,所以什么都不做则返回空对象。
- 首先创建一个空对象
- 将构造函数的作用域指向这个空对象(改变this指向)
- 执行构造函数对this进行加工
- 返回这个对象
js继承的六种方式 https://www.cnblogs.com/ranyonsue/p/11201730.html
function Person(name){ this.name = name}
Person.prototype.age = 10
function Child(){}
// 原型继承
Child.prototype = new Person()
// 构造函数继承
function Child(name){ Person.call(this, name)}
// 原型式继承
function makeObj(obj) {function F(){}; F.prototype = obj; return new F()}
// 寄生组合式
function Child(name) {Person.call(this, name)}
let temp = makeObj(Person.prototype)
Child.prototype = temp
temp.constructer = Child
- 原型继承
通过prototype指向继承父类
缺点:无法传参,且子类的实例共享子类的原型 - 借用构造函数继承 用.call()和.apply()将父类构造函数引入子类函数
缺点:只能继承父类的构造函数,不能继承父类的原型 - 组合继承
结合原形和借用构造函数两种方式
缺点:调用了两次构造函数 - 原型式继承
用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。可用于对象的复制
缺点:所有实例都会继承父类的所有属性,且调用无法复制,无法传参 - 寄生式继承
在原型式继承的基础上对子类自定义
缺点:不能复用 - 寄生组合式继承
通过原型式继承,和寄生式继承 解决了调用两次的问题,注意要修复construtor的指向。而包裹一层new F()主要是为了解决修改子类的原型和父类原型共享问题
js闭包
- js的运行机制:从堆栈的角度看待js函数,基本变量的值一般都是存在栈内存中,而对象类型的变量的值存储在堆内存中,栈内存存储对应空间地址;从全局作用域开始,当程序在调用某个函数时,会准备工作:准备执行环境,初始函数作用域链和arguments参数对象,随着一个函数的执行完毕,函数的执行环境会被销毁释放。
- 变量作用域两种:全局变量、局部变量。js中函数内部可以读取全局变量,函数外部不能读取函数内部的局部变量。
- 那么闭包就是在函数调用完毕以函数返回的形式,让函数作用域链仍被保留,通过闭包可以访问到本来应该被销毁的函数环境。
1、函数作为返回值
2、函数保存变量值:是通过立即执行函数来开辟一个新的函数作用域来保存变量的方法 - 优点
1、读取函数内部的变量
2、让这些变量的值始终保持在内存中。不会再外部函数调用后被自动清除。
3、方便调用上下文的局部变量。利于代码封装。
闭包的使用场景
1、防抖节流函数
2、自由变量 查找的行为类似作用域链,找到定义它的地方,在连续调用时会存储之前的环境进行数据状态的保存,如下会保存第一次函数执行的上下文环境并共享这个变量,所以再次调用的时候会在之前的基础上计算
let t1=(function d(){
var dd=1;
return function(){
return dd++;
};
})();//立即执行
console.log(t1());//1
console.log(t1());//2