/ javascript

javascript原型链

由于现在都是流行写ES5,用class创建对象,对应原型链的理解都不是那么关心了。
之前用ES5,实现面向对象编程,就必须对原型链有一个深入的理解。
下面我画一张图,

-----2019-02-18---11.14.07

1.一种简单对象创建,与继承,就走图上右边的线,代码大致如下

var superO = {};
var subO = {
    __proto__:superO
}
console.log(subO)

subO通过原型继承了superO
2.如果要通过函数来实现继承,用new操作符,这个写法与面向对象语言一样。
从图中可以看出,需要经过构造函数,以及构造函数的构造函数Function绕一圈。
有一点要注意,我也在图中标注了:
Function的原型无法被重新赋值

//Function的原型无法被重新赋值
Function.prototype = {
    say: function () {
        console.log("a")
    }
}
var foo = new Function();
//    foo.say();//无法打印a,程序报错foo.say is not a function

//普通函数原型是可以的
foo.prototype = {
    //这种写法,需要还原构造器,不然foo的构造器会变成object的构造器
    contructor:foo,
    sayFoo: function () {
        console.log("b")
    }
}
//这种方式给原型添加方法,无需还原构造器
foo.prototype.sayFoo1 = function () {
        console.log("b")
    }
var bar = new foo();

bar.sayFoo();//打印b

有了上面这个图,要用ES5实现封装,继承,多态也就不难了。

3.人家都说js灵活,实现继承多种方式,除了覆盖原型的方式,还有
比如下面的call,apply方法

//定义一个add 方法
function add(x, y) {
    return x + y;
}

//用call 来调用 add 方法
function myAddCall(x, y) {
    //调用 add 方法 的 call 方法
    return add.call(this, x, y);
}

//apply 来调用 add 方法
function myAddApply(x, y) {
    //调用 add 方法 的 applly 方法
    return add.apply(this, [x, y]);
}

console.log(myAddCall(10, 20));    //输出结果30
console.log(myAddApply(20, 20));  //输出结果40

4.两者结合也行,把父类的公共方法写在原型上,子类的方法写在函数里面,创建实例的时候,不比给每个实例创建相同的方法,这样可以大大节省内存。