这篇文章将为大家详细讲解有关原生Javascript如何实现继承,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
最近在复习javascript的一些基础知识,为开启新的征程做准备。所以开始记录一些自己学习的内容。
废话少说,上代码!
首先是我们的父类代码。
在这里我们创建一个Person的类作为父类,它的构造函数需要2个参数name和age。
然后我们在它的原型上添加一个sayHi的方法。
//父类 function Person (name, age) { this.name = name || 'no name'; this.age = age || 0; } Person.prototype.sayHi = function () { console.log('Hi, I\'m ' + this.name + ' and i\'m ' + this.age + ' years old!'); } var p = new Person('A',20); p.sayHi();//Hi, I'm A and i'm 20 years old!
//原型继承 function Teacher(){ } Teacher.prototype=new Person('B',22); Teacher.prototype.constructor=Teacher; var t = new Teacher(); t.sayHi();//Hi, I'm B and i'm 22 years old! console.log(t instanceof Person);//true console.log(t instanceof Teacher);//true
从上面的代码来看,Teacher 的实例拥有了 Person 的属性和方法。并且实例对象既是 Person的实例也是 Teacher的实例。而且这种继承方式特别的简单。
我们可以很容易的就发现Teacher类的 name和 age是固定的,都是name=B和age=22,换句话说就是我们无法实现按照我们的意愿给父类的构造函数传参。并且一个我们不能给一个 Teacher 指定多个原型,也就是没法 多继承。然后我们看下下面这段代码:
var t1 = new Teacher(); var t2 = new Teacher(); Teacher.prototype.name = "C"; t1.sayHi();//Hi, I'm C and i'm 22 years old! t2.sayHi();//Hi, I'm C and i'm 22 years old!
上面这段代码中我们可以看到当原型中的属性或者方法被改变时,所有的子类实例的属性和方法也会跟着被改变,也就是原型继承的另一个缺点:所有子类共享同一个原型对象
这里说到了原型,我很早之前也写过一个关于原型的随笔,不过可能也是有些模糊,现在的理解和当时有所不同,我会在后面重新写一篇关于原型的随笔。(写好了我会附上连接)
//构造函数继承 function Teacher (name, age) { Person.call(this, name, age); } var t1 = new Teacher('B', 22); var t2 = new Teacher('C', 30); console.log(t1.name);//B console.log(t2.name);//C console.log(t1 instanceof Person);//false console.log(t1 instanceof Teacher);//true t1.sayHi();//TypeError: t1.sayHi is not a function t2.sayHi();//TypeError: t1.sayHi is not a function
相对于 原型继承 , 构造函数继承解决了所有的子类实例共享统一原型的问题,也可以给父类的构造函数传参,并且我们可以在子类的构造函数中调用多个父类的构造函数,实现所谓的多继承(这里的多继承是指子类通过call,apply等方法去调用父类的构造函数使其拥有父类的属性和方法,但是js中一个函数对象只存在一个 prototype,所以其实我们没法通过原型链的形式去体现出多继承)
上面的代码中我们可以看出创建的实例只是 子类的实例 并不是 父类的实例 ,不能直观的体现出继承,这种继承方式也无法继承父类的原型上的属性和方法。
//组合式继承 function Teacher (name, age) { Person.call(this, name, age); } Teacher.prototype = new Person(); Teacher.prototype.constructor = Teacher; var t1 = new Teacher('B', 22); var t2 = new Teacher('C', 30); Teacher.prototype.name = "D"; console.log(t1.name);//B console.log(t2.name);//C t1.sayHi();//Hi, I'm B and i'm 22 years old! t2.sayHi();//Hi, I'm C and i'm 30 years old! console.log(t1 instanceof Person);//true console.log(t1 instanceof Teacher);//true
组合式继承就是结合了原型继承和构造函数继承的优点,解决了两种方式存在的一些缺点。但是我们会发现每当我们去创建一个子类实例的时候都会去创建一个父类的实例,尽管父类实例不是同一个实例(内存地址不一样),但是他们其实属性和方法上完全一致,所以我们通过下面这种(寄生式组合继承)方式完善它,以避免不必要的实例构造。
//寄生式组合继承 function Teacher (name, age) { Person.call(this, name, age); } Teacher.prototype = Object.create(Person.prototype); Teacher.prototype.constructor = Teacher; var t1 = new Teacher('B', 22); var t2 = new Teacher('C', 30); Teacher.prototype.name = "D"; console.log(t1.name);//B console.log(t2.name);//C t1.sayHi();//Hi, I'm B and i'm 22 years old! t2.sayHi();//Hi, I'm C and i'm 30 years old! console.log(t1 instanceof Person);//true console.log(t1 instanceof Teacher);//true
上面的方式解决了我们没创建一个子类实例都去创建一个父类实例的问题,这也是最为常用的一种js的继承方式,如果我们通过Babel去把ES6中的class的继承转成ES5的代码,我们会发现就是用的寄生式组合继承。
关于“原生Javascript如何实现继承”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。