7种继承方式的比较(js)

    科技2023-09-30  79

    前言

    对于js这种面向过程的编程语言而言,oo不是它的强项,但有时也会在代码中OOP。 这里收集了七种继承方式,并测试做了比较。还有一些其他的实现形式暂未考虑,比如通过拷贝的形式实现继承; 由于技术原因,具体用到哪些场景不是很在行,所以这里就做一些简单的示范和介绍。

    代码

    /** * https://www.cnblogs.com/qing-5/p/11365614.html * 父级构造函数中的属性在子级实例上有一份在原型上有一份(多余),浪费内存 */ /* function A(name) { this.name = name; this.propertys = { sex: "F" }; } A.prototype.sayName = function() { console.log("A.prototype.sayName===", this.name); }; A.prototype.sayName2 = function() { console.log("A.prototype.sayName===", this.name); }; function B(age, name) { A.call(this, name); // this.age = age; this.propertys = { sex: "M" }; } B.prototype = new A(); // B.prototype.constructor = B; // B.prototype.sayName = function() { console.log("B.prototype.sayName===", this.name); }; B.prototype.sayAge = function() { console.log("B.prototype.sayAge===", this.age); }; var a = new A("aaa"); var b = new B(22, "bbb"); a.sayName(); b.sayName(); b.sayAge(); console.log("a===", a); console.log("b===", b); console.log("a.__proto__", a.__proto__); console.log("b.__proto__", b.__proto__); */ /** * es6 class语法糖 * 不继承构造器里面的属性 * 代码易维护 */ /* class A { constructor(name) { this.name = name; } sayName() { console.log("A.prototype.sayName===", this.name); } } class B extends A { constructor(age, name) { super(name); this.name = name; this.age = age; } sayName(name) { console.log("B.prototype.sayName===", this.name); } sayAge() { console.log("B.prototype.sayAge===", this.age); } } var a = new A("aaa"); var b = new B(22, "bbb"); a.sayName(); b.sayName(); b.sayAge(); console.log("a===", a); console.log("b===", b); console.log("a.__proto__", a.__proto__); console.log("b.__proto__", b.__proto__); */ // /** * <<ES6标准入门 9.11>> * 实例之间的无构造函数的继承 * 要产生多个对象需要克隆并一一改变它们的属性 */ /* var a = { name: "aaa", superName: "aaa_super", propertys: [{ _a: "_a" }], sayName() { console.log("a.sayName:", this.name); } }; var b = Object.create(a); // var b = Object.assign( // Object.create(a), { // name: 'bbb' // } // ); b.name = "bbb"; b.age = 22; b.sayAge = function() { console.log("b.sayAge:", this.age); } a.sayName(); b.sayName(); //能调用原型上的方法 b.sayAge(); b.propertys[0]._b = "_b"; //能改原型上的对象 console.log("a===", a); console.log("b===", b); console.log("a.__proto__", a.__proto__); //Object.prototype console.log("b.__proto__", b.__proto__); */ /** * http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html * 构造函数绑定 * 通过子类构造函数中,绑定父类this上的方法:A.call(this, name); * 只能访问父类构造函数内定义的属性和方法,不能访问父类原型上的 * 子级实例上的属性拥有父级实例一样的属性,实际上消耗了内存换取了速度,因为在原型上查询是耗时的 */ /* function A(name) { this.name = name; this.propertys = { sex: "F" }; this._a = "_a"; } A.prototype.sayName = function() { console.log("A.prototype.sayName===", this.name); }; A.prototype.say = function() { console.log("A.prototype.say===", this._a); }; function B(age, name) { //继承属性 使用借用构造函数实现对实例属性的继承 A.call(this, name); this.name = name; //覆盖属性 this.age = age; //父级构造函数中的this上不会有age属性 this.propertys = { sex: "M" }; } B.prototype.sayName = function() { //覆盖方法 console.log("B.prototype.sayName===", this.name); }; B.prototype.sayAge = function() { //自定义方法 console.log("B.prototype.sayAge===", this.age); }; */ /** * http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html * prototype模式 * 通过子级构造函数的prototype设置为父级实例,并改变constructor指向 * B.prototype = new A();   * B.prototype.constructor = B; * 子集对象的原型上有父级对象上的构造函数中的方法和属性,子级对象可以使用父级对象构造函数和原型上的方法属性 * 子级原型上有一个父级构造函数中相同的副本,额外增加了内存消耗,也容易发生命名冲突 */ /* function A(name) { this.name = name; this.propertys = { sex: "F" }; this._a = "_a"; } A.prototype.sayName = function() { console.log("A.prototype.sayName===", this.name); }; A.prototype.say = function() { console.log("A.prototype.say===", this._a); }; function B(age, name) { this.name = name; this.age = age; this.propertys = { sex: "M" }; } B.prototype = new A("aa");   B.prototype.constructor = B; B.prototype.sayName = function() { //覆盖方法 console.log("B.prototype.sayName===", this.name); }; B.prototype.sayAge = function() { //自定义方法 console.log("B.prototype.sayAge===", this.age); }; B.prototype.name = "B.prototype.name"; */ /** * http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html * 直接继承prototype(共享prototype) * 子级的构造函数的prototype上定义的东西会覆盖父级的,他们相互影响 * 省内存 */ /* function A(name) { this.name = name; this.propertys = { sex: "F" }; this._a = "_a"; } A.prototype.sayName = function() { console.log("A.prototype.sayName===", this.name); }; A.prototype.say = function() { console.log("A.prototype.say===", this._a); }; function B(age, name) { this.name = name; this.age = age; this.propertys = { sex: "M" }; } B.prototype = A.prototype;   B.prototype.constructor = B; B.prototype.sayName = function() { //覆盖方法 console.log("B.prototype.sayName===", this.name); }; B.prototype.sayAge = function() { //自定义方法 console.log("B.prototype.sayAge===", this.age); }; B.prototype.name = "B.prototype.name"; */ /** * http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html * 直接继承prototype(空函数中介) * 父子(实例/原型)上的属性和方法都泾渭分明 * 调用父级原型上的方法this会错误,需显式改变this指向 */ /* function A(name) { this.name = name; this.propertys = { sex: "F" }; this._a = "_a"; } A.prototype.sayName = function() { console.log("A.prototype.sayName===", this.name); }; A.prototype.say = function() { console.log("A.prototype.say===", this._a); console.log("A.prototype.say | this===", this); }; function B(age, name) { this.name = name; this.age = age; this.propertys = { sex: "M" }; } var F = function() {}; F.prototype = A.prototype B.prototype = new F();   B.prototype.constructor = B; B.prototype.sayName = function(a) { console.log("B.prototype.sayName===", this.name); }; B.prototype.sayAge = function() { console.log("B.prototype.sayAge===", this.age); }; B.prototype.name = "B.prototype.name"; */ // var a = new A("aaa"); // var b = new B(22, "bbb"); // a.sayName(); // b.sayName(); // b.sayAge(); // console.log("a===", a); // console.log("b===", b); // // console.log("A.name===", A.name); // // console.log("B.name===", B.name); // console.log("a.__proto__", a.__proto__); // console.log("b.__proto__", b.__proto__);

    不足

    1、没考虑混入(多继承)。 2、具体应用场景。 3、更多的继承方式。

    Processed: 0.013, SQL: 8