简单记录两种js实现继承方式的比较
方案A
// 寄生组合式继承 function clone(parent, child) { // 使用Object.create()方法创建一个新的对象,并将其原型指向父类的原型对象 child.prototype = Object.create(parent.prototype); child.prototype.constructor = child; } // 父类 function Parent() { this.name = '我是父类中的name'; this.play = ['打篮球', '踢足球']; } // 父类原型方法 Parent.prototype.getName = function () { return this.name; } // 子类 function Child() { Parent.call(this); this.friend = '我是子类中的friend'; } // 寄生组合式继承 clone(Parent, Child); // 子类原型方法 Child.prototype.getFriend = function () { return this.friend; } let child1 = new Child(); let child2 = new Child(); console.log(child1.getName()); // 我是父类中的name console.log(child1.getFriend()); // 我是子类中的friend console.log(child1.play); // ['打篮球', '踢足球'] child1.play.push('打羽毛球'); console.log(child1.play); // ['打篮球', '踢足球', '打羽毛球'] console.log(child2.play); // ['打篮球', '踢足球']
方案B:
// 寄生组合式继承 function clone(parent, child) { // 创建一个中间函数F,避免直接修改父类的原型对象 function F() {} F.prototype = parent.prototype; child.prototype = new F(); child.prototype.constructor = child; } // 父类 function Parent() { this.name = '我是父类中的name'; this.play = ['打篮球', '踢足球']; } // 父类原型方法 Parent.prototype.getName = function () { return this.name; } // 子类 function Child() { Parent.call(this); this.friend = '我是子类中的friend'; } // 寄生组合式继承 clone(Parent, Child); // 子类原型方法 Child.prototype.getFriend = function () { return this.friend; } let child1 = new Child(); let child2 = new Child(); console.log(child1.getName()); // 我是父类中的name console.log(child1.getFriend()); // 我是子类中的friend console.log(child1.play); // ['打篮球', '踢足球'] child1.play.push('打羽毛球'); console.log(child1.play); // ['打篮球', '踢足球', '打羽毛球'] console.log(child2.play); // ['打篮球', '踢足球']
增加一下小案例,给自己方便记忆
// 1. 定义父类 function Parent(name) { this.name = name; } Parent.prototype.sayName = function() { console.log(`Parent says my name is: ${this.name}`); }; // 2. 定义子类,并使用 Object.create 的第二个参数 function Child(name, age) { // 借用构造函数继承父类实例属性 Parent.call(this, name); this.age = age; } // 核心代码:建立原型链 + 同时定义子类原型属性 Child.prototype = Object.create(Parent.prototype, { // 属性 1:普通方法(注意:默认情况下,通过这种方式定义的属性,enumerable 为 false) sayHello: { value: function() { console.log(`Hello! I am ${this.name}, ${this.age} years old.`); }, writable: true, // 是否可以修改 enumerable: false, // 不可枚举(for...in 遍历不到) configurable: true // }, // 属性 2:使用 getter/setter ageInfo: { get: function() { return `${this.name} is ${this.age} years old.`; }, enumerable: true, configurable: true } }); // 别忘了修正 constructor 指向(因为 Object.create 创建的是纯净空对象) Child.prototype.constructor = Child; // 3. 测试运行 const child1 = new Child('张三', 18); // 测试父类原型方法 child1.sayName(); // 输出: Parent says my name is: 张三 // 测试通过第二参数定义的子类方法 child1.sayHello(); // 输出: Hello! I am 张三, 18 years old. // 测试 getter 属性 console.log(child1.ageInfo); // 输出: 张三 is 18 years old. // 验证 constructor 指向 console.log(child1.constructor === Child); // 输出: true // 验证不可枚举特性 for (let key in child1) { console.log(key); } // 输出: name, age, ageInfo // (注意:sayHello 没有打印出来,因为它是不可枚举的)
emm,这坨东西是真的麻烦,我直接一手ES6的 extends 语法糖,直接解决
浙公网安备 33010602011771号