原型链
原型链知识
prototype:只有函数有prototype属性,Object是构造函数,所以有该属性
proto:对象的原型。(a.proto===Object.getPrototypeOf(a))
proto是实例对象和构造函数之间的连接。它的值是构造函数的prototype
每个对象都有一个原型对象,对象的原型对象也可能是继承自其他的原型对象,一层一层以此类推,构成了原型链
原型链的终点就是Object.prototype
如a = new A() a.proto === A.prototype A.prototype.proto = Object.prototype
一图搞懂原型链
Object.setPrototypeOf() : 设定一个指定对象的原型 如Object.setPrototypeOf(A,B),将A的原型设置为B
Object.getPrototypeOf():获取一个对象的原型
继承
原理
何为继承
原型链继承
原理 :sonFn.prototype = new fatherFn()
缺点
- 父类this声明的属性被所有子类共享
-
构造函数继承
原理:在子函数中调用父函数,使用call改变this指向
fatherFn(par){
this.arr = par
}
sonFn(params){
fatherFn.call(this,...params)
}
fatherF执行this指向类sonFn,所以fatherFn中的this声明都声明到sonFn下面了。
缺点 未对父类的prototype 做任何处理,所以无法继承父类prototype上的属性类方法。
- 父类的方法无法复用。
组合继承
原理:利用原型链继承和构造函数继承 ```javascript fatherFn(params){ this.arr = params } fatherFn.prototype.name = ‘fatherFn 组合继承’ sonFn(params){ fatherFn.call(this,…params) //构造函数继承 } sonFn.protptype = new fatherFn() //原型链继承
能完整的继承父级函数的prototype和this<br />缺点
- 两次调用父级,造成性能损耗
- 生成两份父级的this
- 父类的prototype上的属性和方法都在子类上,造成父类的原型链丢失
<a name="hinYc"></a>
#### 原型式继承
原理:通过Object.create() ,实现原理如下
```javascript
function myCreate(obj){
function F(){}
F.prototype = obj
return new F()
}
//使用
let fatherObj = {name:'yhd'}
let sonObj = myCreate(fatherObj) // sonObj 就可以继承fatherObj的内容
兼容性好,最简单的对象继承。
缺点:
- 无法传参
- 因为旧对象(oldObj)是实例对象(newObj)的原型,多个实例共享被继承对象的属性,存在篡改的可能。
寄生式继承
原理:基于原型式继承,封装一层函数,在函数中丰富对象 ```javascript // 基于前面的原型式继承 function fullCreate(obj){ let some = myCreate(obj) some.fn = function(){}//丰富函数 some.age = 18 return some }
专门为对象做某种固定方式的丰富。
<a name="hgkU8"></a>
#### 寄生组合式继承
原理:基于构造函数继承和寄生式继承<br />用寄生继承弥补构造函数继承未处理father.prototype的问题
```javascript
function fatherFn(arr){
this.name = 'father的Name'
this.params = ...arr
}
fatherFn.ptototype.fn = 'father的prototype 上的fn'
function sonFn(arr){
this.name = 'son 的name'
fatherFn.call(this,...arr) //将fatherFn中的this 指向 sonFn
}
function myExtends(son,father){
//浅克隆father.prototype
const fatherPrototype = Object.create(father.prototype)
// 将son的prototype 继承father.prototype
son.prototype = fatherPrototype
// 修正constructor指向
son.construtor = son
}
myExtends(sonFn,fatherFn)
寄生组合式继承式目前最成熟的继承方式,有如下优点
- 只调用一次fatherFn函数、
- 避免在子类prototype上创建不必要多余属性
- 使用原型式继承父类prototype,保持了原型链上下文不变
ES6 extends继承
原理:寄生组合式继承// 寄生式继承 封装继承过程
function _inherits(son, father) {
// 原型式继承: 设置father.prototype为son.prototype的原型 用于继承father.prototype的属性/方法
son.prototype = Object.create(father && father.prototype);
son.prototype.constructor = son; // 修正constructor 指向
// 将父类设置为子类的原型 用于继承父类的静态属性/方法(father.some)
if (father) {
Object.setPrototypeOf
? Object.setPrototypeOf(son, father)
: son.__proto__ = father;
}
}
迭代器和生成器
迭代器(iterator)
含义:
为各种数据结构提供提供统一访问机制,任何数据结构只要部署 iterator接口,就能完成遍历操作。
作用:
- 为各种数据结构提供统一访问接口
- 使数据结构成员能按照一定顺序排列
- 主要为for of服务
原生具备iterator接口的数据格式(可直接使用for…of..)
- Array
- map
- set
- string
- 函数的arguments
-
迭代器工作原理
创建一个指针,指向数据机构起点
- 第一次调用next()方法,指针自动指向数据结构第一个成员
- 接下来不断调用next()方法,指针也不断后移,直到指向最后一一个成员
- next()方法返回对象包含value 和done对象,{value:当前成员的值,done:布尔值}
value表示当前成员的值,done表示是否结束遍历
遍历结束时value返回undefined ,done返回true
function myIterator (arr) {
let arrIndex = 0
return {
next: function () {
if (arrIndex > arr.length) {
return {
value: undefined,
done: true
}
} else {
arrIndex++
return {
value: arr[arrIndex - 1],
done: false
}
}
}
}
}
const arr = ['a', 'b', 3, 'd']
const iteratorFn = myIterator(arr)
console.log(iteratorFn.next())
console.log(iteratorFn.next())
console.log(iteratorFn.next())
console.log(iteratorFn.next())
console.log(iteratorFn.next())
注意点:
for of不支持对象,对象的Symbol.iterator属性,指向该对象的默认遍历器方法。当使用for of去遍历某一个数据结构的时候,首先去找Symbol.iterator,找到了就去遍历,没有找到的话不能遍历,提示Uncaught TypeError: XXX is not iterable
当使用扩展运算符(…)或者对数组和 Set 结构进行解构赋值时,会默认调用Symbol.iterator方法
生成器(Generator)
概念:
- Generator函数是ES6提供的异步编程解决方案,语法行为于传统函数不同
- Generator函数是一个状态机,封装了多种内部状态
- Generator函数除了是状态机,还是遍历器对象生成函数
- 可暂停函数,yield可暂停,next可启动,
分段执行
function* myGenerator () {
yield 111
yield '22222'
}
const fn = myGenerator()
console.log(fn.next())//{value: 111, done: false}
console.log(fn.next())//{value: ‘22222’, done: false}
Generator 函数是分段执行的,调用next方法函数内部逻辑开始执行,遇到yield表达式停止,返回{value: yield后的表达式结果/undefined, done: false/true},再次调用next方法会从上一次停止时的yield处开始,直到最后。
next传递参数
yield本身返回undefined,当next() 携带参数,该参数会当作上一个yield的返回值
与iterator迭代器关系
generator本来就是遍历器生成函数,可以将generator赋值给对象的[symbol.iterator]属性,从而使得该对象具有iterator接口
let obj = { username: 'kobe', age: 39 }
obj[Symbol.iterator] = function* myTest() {
yield 1;
yield 2;
yield 3;
};
for (let i of obj) {
console.log(i) // 1 2 3
}
function iteratify(obj) {
obj[Symbol.iterator] = function * () {
for(let prop of Object.getOwnPropertyNames(this)) {
yield this[prop]
}
}
}
map filter reduce
promise
proxy