每日复习------继承与迭代

334 阅读3分钟

继承

构造函数继承

优点

  1. 相比原型链。可以在子类的构造函数中 向父类传递参数

缺点

  1. 必须 在构造函数中定义方法,且函数不能重用
  2. 子类无法访问 父类 原型链上的方法
function Father(name){
    this.colors= ["red", "blue","green"]
}

function Son(){
    //继承 Father
    Father.call(this,'Father');
}


let instance= new Son()
Son.colors.push("black ")
console.log(Son.colors); //"red, blue, green, black.
let instance= new Son()
console.log (instance. colors);//"red, blue, green

组合继承

优势

  1. 结合了原型链和 构造函数继承
  2. 保留了 instanceofisPrototypeOf()方法
function Father(name){
    this.colors= ["red", "blue","green"]
	this.name= name
}

Father.prototype.sayName = function(){
    console.log(this.name);
}

function Son(name, age){
    // 继承属性
    Father.call(this, name)
    this.age=age
}
// 继承方法
Son.prototype = new Father()
Son.prototype.sayAge = function(){
    console.log(this.age)
}

let instance= new Son("Nicholas", 29)
instance.colors.push("black")
console.log(instance.colors);//"red, blue, green, black
instance.sayName()  //Nicholas
instance.savAge() //29

let instance2= new Son("Greg", 27)
console.log (instance.colors);//"red, blue, green
instance2.sayName()//"Greg"
instance2.savAge()//27

深拷贝继承

function Person(name){
    this.name = name;
}
Person.prototype.say = function(){
    console.log('hello person')
}


function Student(name){
    Person.call(this,name)
}

function deepCopy(obj){
    let newObj = Array.isArray(obj)?[]:{}
    for(let i in obj){
        if(obj.hasOwnProperty(i)){
            if (typeof i === 'Object'){
            newObj[i] = deepObj(obj[i])
        }else{
            newObj[i] = obj[i]
        }
       }
    }
    return newObj
}


Student.prototype = deepCopy(Person.prototype)
Student.prototype.constructor = Student // 把预定义属性改回来
Student.prototype.say = function(){
    console.log('hello Student')
}

let stu = new Student()
let per = new Person()
stu.say() // hello Student
per.say() // hello person

寄生组合继承

  1. 解决了 组合继承效率问题( 调用两次父类)
function Father(name){
    this.colors= ["red", "blue","green"]
	this.name= name
}

Father.prototype.sayName = function(){
    console.log(this.name);
}
function Son(name, age){
    Father.call(this, name)
    this.age=age
}
Son.prototype = new Father()
Father.prototype.constructor= Son //第一次调用 SuperType()

Son.prototype.sayAge = function(){
    console.log(this.age)
}

以下不借助构造函数

简单原型继承

影响: 影响父类

function Person(name){
    this.name = name;
}
Person.prototype.say = function(){
    console.log('hello person')
}
function Student(name){
    this.eyes = "两小只";
}
Student.prototype = Person.prototype  //直接赋值


Student.prototype.say = function(){
    console.log('hello Student')
}

let stu = new Student()
let per = new Person()
stu.say() // hello Student
per.say() // hello Student

组合继承

解决简单原型继承的问题

function Person(name){
    this.name = name;
}
Person.prototype.say = function(){
    console.log('hello person')
}


function Student(name){
    this.eyes = "两小只";
}

function mid(){
    
}
mid.prototype = Person.prototype // 利用空函数来


Student.prototype = new mid()
Student.prototype.constructor = Student // 把预定义属性改回来

Student.prototype.say = function(){
    console.log('hello Student')
}

let stu = new Student()
let per = new Person()
stu.say() // hello Student
per.say() // hello person

迭代器与可迭代协议

在日常使用中

let arr = [1,2,3]
for (let arrKey in arr) {
  console.log(arrKey)
}
for (let number of arr) {
  console.log(number)
}
//  上述可以执行   下述不可以 报错
//  TypeError: obj is not iterable
let obj = {
  1:'a',
  2:'b',
  3:'c',
}

for (let objKey in obj) {
  console.log(objKey)
}

for (let objElement of obj) {
  console.log(objElement)
}

为什么 数组可以使用forobj不可以

首先,先要 明白两个协议

  1. 可迭代协议
  2. 迭代器协议

了解到。数组 和 obj 差别在于[Symbol.iterator]

接下来我们就在对象里面实现这个协议.

根据 迭代器协议 可知。 我们需要 返回一个对象。 对象里面包含next方法。还要包含donevalue属性(具体请见迭代器协议

let obj = {
  1:'a',
  2:'b',
  3:'c',
}
obj[Symbol.iterator] = function(){
  let objValues = Object.values(obj)
  let index = 0

  return {
    next(){
      if(index >= objValues.length){
        return {
          done: true
        }
      } else {
        return {
          done: false,
          value:  objValues[index++]
        }
      }
    }
  }
}
for (let objKey in obj) {
  console.log(objKey) // 1 2 3 
}

for (let objElement of obj) {
  console.log(objElement)  // a b c
}

这时候我们就可以让obj进行循环了

Generator

有关Generator 就不在多做叙述了。没有了解的请查看阮一峰老师的ES6入门

这里提供一个简单的例子

function* fn(){
    yield 1;
    yield 2;
    yield 3;
}
let f = fn();
//console.log(f); // 返回一个函数 不会立即执行
//console.log(f.next());  // 输出类似 迭代器的返回对象 
for(let val of f){
    console.log(val); // 1 2 3 
}

做异步

function*fn(){
    yield new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("a");
            resolve(1);
        },500);
    });
    yield new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("b");
            resolve(2);
        },500);
    });
    yield new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log("c");
            resolve(3);
        },500);
    });
}
// 会一起执行
//let f = fn()
//for (let fElement of f) {
//  console.log(fElement)
//}

function co(fn){
    let f = fn(); // 返回了一个可迭代

    function next(data){
        let result = f.next();
        console.log(result) // {done:  value: promise}
        if(!result.done){
            // 上一个异步走完了,再执行下一个异步
            result.value.then((info)=>{
                console.log(info,data);
                next(info);
            });
        }
    }
    next();
}
co(fn);

由上面注释可知。如果我们用 for 直接迭代。则会直接执行。但是我们希望它会分步执行。所以这时候就需要了一个函数 (同时也是以可库co)

co 函数的作用,根据 Generator每个返回值 { done:false/true value: Promise}. 根据 donepromise执行完在执行下个 类似于 Async/ await