javascript-类的继承,call手动实现...

100 阅读3分钟

看代码写结果

    var a = {n:4}; 
    var b = a; 
    b.x = a = {n: 10}; 
    console.log(a.x); // undefined 
    console.log(b.x); // {n:10}

解析:先开辟一块堆内存,用来存储{n:4}这个对象,a,b指向这个堆内存地址(AAAFFF),执行到第三部得到这个(AAAFFF)地址对应的对象{n:4,x:BBBFFF},a又重新指向新的堆内存地址(BBBFFF),存放着{n:10}

写出你掌握的继承方法

//call继承
function Father(name){
    this.name=name
}
function Son(name,age){
    Father.call(this,name)
    this.age=age
}

//原型继承
const father=Object.create(Father.prototype)
Son.prototype=father

//call与原型继承结合-->寄生组合式继承

//es6的class继承

class Parent{
    constructor(name){
        this.name=name
    }
    eat(){
        console.log("吃")
    }
}

class Son extends Parent{
    constructor(name,age){
        super(name)
        this.age=age
    }
}

关于类的继承的总结

在es6之前使用function来定义类的,(既代表方法,又代表类,又代表一个方法实例(对象))

原型继承: 就是子类要继承父类原型上的方法,原理就是让子类的prototype是父类的一个实例,这样子类的实例就可以通过原型链的查找使用父类的方法

Object.create(Father.prototype)得到Father类的的空实例(没有私有属性)

call继承: 就是子类也想有父类同名的私有属性,通过call调用父函数,改变内部的this指向,指向当前的子类的实例,这样就为子类的实例上添加了与父类同名的私有属性

寄生组合式继承: 就是结合call继承与原型继承把父类的私有属性,与prototype上的方法一同继承过来

class继承: 使用extends和super,super相当于call继承,如果在子类的prototype的方法中使用super,super代表父类的prototype(原型对象)

也有一种方式就是让实例的__proto__等于父类的prototype,就可以使用父类方法

call&&apply&&bind的区别

call和apply和bind都是Function原型对象上的方法,所以对于所有的方法实例都可以调用,第一个参数用来改变函数内部this指向,之后的参数就是为调用他们方法传递参数,call传递参数的方式是一个一个传,apply只能传递一个数组,也就是说apply最多传递两个参数,第一个参数就是改变函数内部this指向的,第二个参数是个数组,bind方法并不是让调用着立即执行他会返回一个新的函数,再调用返回的函数时再调用之前那个函数,同时改变内部this指向,如果调用call apply bind时一个参数都不传,内部的this指向window

手动实现call方法

//先处理不传参数的情况,再处理传入的参数是基本数据类型的情况
function myCall(context,...args){
    //如果不传参数,那么就改变函数的内部this指向为window
    if(context==null){
        context=window
    }
    //如果传入的是基本数据类型,把它转化成引用数据类型
    if(!/^(function|object)$/.test(typeof context)){
        if(/^(symbol|bigInt)$/.test(typeof context)){
            context=Object(context)
        }else{
           context = new context.constructor(context)
        }
    }
    //现在context一定是引用数据类型
    let sym=Symbol("123")
    context[sym]=this
    let res=context[sym](...args)
    delete context[sym]
    return res
}
["myCall","myApply","myBind"].forEach(item=>{
    Function.prototype[item]=eval(item)
})