一对象冒充
其原理如下: 构造函数使用 this 关键字给所有属性和方法赋值 (即采用类声明的构造函数方式) 因为构造函数只是一个函数, 所以可使 Parent 构造函数
成为 Children 的方法, 然后调用它 Children 就会收到 Parent 的构造函数中定义的属性和方法例如, 用下面的方式定义 Parent 和 Children:
- // 父类构造函数
- var Parent = function(name){
- this.name = name;
- this.sayHi = function(){
- console.log("Hi!" + this.name + ".");
- }
- };
- // 子类构造函数
- var Children = function(name){
- this.method = Parent;
- this.method(name); // 实现继承的关键
- delete this.method;
- this.getName = function(){
- console.log(this.name);
- }
- };
- var p = new Parent("john");
- var c = new Children("joe");
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! joe.
- c.getName(); // 输出: joe
原理其实很简单: 就是把 Parent 构造函数放到 Children 构造函数里面执行一次那为什么不直接执行, 非要转个弯把 Parent 赋值给 Children 的 method 属性再执行呢?
这跟 this 的指向有关, 在函数内 this 是指向 window 的当将 Parent 赋值给 Children 的 method 时, this 的就指向了 Children 类的实例如果想了解在 JavaScript 内部
this 的工作原理可以看下本人之前发的一片文章详解 this 的工作原理
二原型链继承
众所周知 JavaScript 是一门基于原型的语言, 在 JavaScript 中 prototype 对象的任何属性和方法都被传递给那个类的所有实例原型链利用这种功能来实现继承机制:
- // 父类构造函数
- var Parent = function(){
- this.name = "john";
- this.sayHi = function(){
- console.log("Hi!" + this.name + ".");
- }
- };
- // 子类构造函数
- var Children = function(){};
- Children.prototype = new Parent(); // 实现继承的关键
- var p = new Parent();
- var c = new Children();
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! john.
注意: 调用 Parent 的构造函数, 没有给它传递参数这在原型链中是标准做法要确保构造函数没有任何参数
三使用 call 或 applay 方法
这个方法是与对象冒充方法最相似的方法, 因为它也是通过改变了 this 的指向而实现继承:
- // 父类构造函数
- var Parent = function(name){
- this.name = name;
- this.sayHi = function(){
- console.log("Hi!" + this.name + ".");
- }
- };
- // 子类构造函数
- var Children = function(name){
- Parent.call(this, name); // 实现继承的关键
- this.getName = function(){
- console.log(this.name);
- }
- };
- var p = new Parent("john");
- var c = new Children("joe");
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! john.
- c.getName(); // 输出: joe
apply 方法本人就不举列了, 它和 call 方法的区别在于它的第二个参数必须是数组
四混合方式
对象冒充的主要问题是必须使用构造函数方式, 这不是最好的选择不过如果使用原型链, 就无法使用带参数的构造函数了如何选择呢? 答案很简单, 两者都用
在 JavaScript 中创建类的最好方式是用构造函数定义属性, 用原型定义方法这种方式同样适用于继承机制:
- // 父类构造函数
- var Parent = function(name){
- this.name = name;
- };
- Parent.prototype.sayHi = function(){
- console.log("Hi!" + this.name + ".");
- };
- // 子类构造函数
- var Children = function(name, age){
- Parent.call(this, name); // 实现继承的关键
- this.age = age;
- };
- Children.prototype = new Parent(); // 实现继承的关键
- Children.prototype.getAge = function(){
- console.log(this.age);
- };
- var p = new Parent("john");
- var c = new Children("joe",30);
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! joe.
- c.getAge(); // 输出: 30
五使用 Object.create 方法
Object.create 方法会使用指定的原型对象及其属性去创建一个新的对象:
- // 父类构造函数
- var Parent = function(name){
- this.name = name;
- };
- Parent.prototype.sayHi = function(){
- console.log("Hi!" + this.name + ".");
- };
- // 子类构造函数
- var Children = function(name, age){
- Parent.call(this, name); // 实现继承的关键
- this.age = age;
- };
- Children.prototype = Object.create(Parent.prototype); // 实现继承的关键
- Children.prototype.constructor = children; // @
- Children.prototype.getAge = function(){
- console.log(this.age);
- };
- var p = new Parent("john");
- var c = new Children("joe",30);
- p.sayHi(); // 输出: Hi! john.
- c.sayHi(); // 输出: Hi! joe.
- c.getAge(); // 输出: 30
@ 当执行 Children.prototype = Object.create(Parent.prototype) 这个语句后, Children 的 constructor 就被改变为 Parent , 因此需要将 Children.prototype.constructor 重
新指定为 Children 自身
六 extends 关键字实现继承
这个是 ES6 的语法糖, 本人就不班门弄斧了, 详细的细节大家可以看看这个文章 Class 的继承
来源: http://www.qdfuns.com/notes/47066/d025ef5b23867e28ab786678bb41e9a8.html