es6继承 vs js原生继承(es5)

最近在看es2015的一些语法,最实用的应该就是继承这个新特性了。比如下面的代码:

 1 $(function(){
 2     class Father{
 3         constructor(name, age){
 4              this.name = name;
 5              this.age = age;
 6         }
 7
 8         show(){
 9             console.log(`我叫:${this.name}, 今年${this.age}岁`);
10         }
11     };
12     class Son extends Father{};
13
14     let son = new Son(‘金角大王‘, 200);
15     son.show();//return 我叫:金角大王, 今年200岁
16
17 });

这是一个最简单的继承。在Son类中并没有任何的自己的属性和方法,来看一下f12中的结构

也是不例外的使用了原型链来实现的继承,那么在es5中如果要实现这个继承应该怎么做?

使用babel把这段代码翻译成es5的语法,发现代码如下:

 1 "use strict";
 2
 3 var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
 4
 5 function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn‘t been initialised - super() hasn‘t been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 6
 7 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
 8
 9 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10
11 /**
12  * Created by liuyc14 on 2016/6/28.
13  */
14
15 var Father = function () {
16     function Father(name, age) {
17         _classCallCheck(this, Father);
18
19         this.name = name;
20         this.age = age;
21     }
22
23     _createClass(Father, [{
24         key: "show",
25         value: function show() {
26             console.log("我叫:" + this.name + ", 今年" + this.age + "岁");
27         }
28     }]);
29
30     return Father;
31 }();
32
33 ;
34
35 var Son = function (_Father) {
36     _inherits(Son, _Father);
37
38     function Son() {
39         _classCallCheck(this, Son);
40
41         return _possibleConstructorReturn(this, Object.getPrototypeOf(Son).apply(this, arguments));
42     }
43
44     return Son;
45 }(Father);
46
47 ;

这些是babel编译完成后生成的es5语法的实现代码,看起来多了很多东西。

不着急,挑出几个重点来看一下(以后的例子都使用es5语法

1. _createClass 方法,创建一个类,用到了defineProperties方法,就是给第一个参数的target对象,附加所有第二个参数的属性

2. _inherits 方法,实现继承的核心,用到了Object.create 和 Object.setPrototypeOf 方法

Object.create 方法:

这个方法接受两个参数,第一个参数为要继承的对象,第二参数为附加属性,返回一个创建后的对象。

举个例子:

 1 function Father(name, age){
 2     this.name = name;
 3     this.age = age;
 4 }
 5
 6 Father.prototype.show = function () {
 7     console.log(‘我叫:‘ +this.name+‘, 今年‘+this.age+‘岁‘);
 8 };
 9
10 var obj = Object.create(Father.prototype);
11 console.log(obj.name); //return undefined
12 obj.show(); // return 我叫:undefined, 今年undefined岁

上面这个例子中,使用create方法,创建了一个obj对象,而且这个对象继承了Father.prototype对象的属性。(只有一个show方法,并没有 name 和 age 属性)

看到了这个作用以后,我们就可以使用create方法来实现es5的继承了

 1 function Father(name, age){
 2     this.name = name;
 3     this.age = age;
 4 }
 5
 6 Father.prototype.show = function () {
 7     console.log(‘我叫:‘ +this.name+‘, 今年‘+this.age+‘岁‘);
 8 };
 9
10 function Son(name, age){
11     Father.call(this, name, age);
12 }
13 Son.prototype = Object.create(Father.prototype);
14 Son.prototype.constructor = Son;
15 Son.prototype.show = function () {
16     console.log(‘我是子类,我叫‘ + this.name + ‘, 今年‘ + this.age + ‘岁了‘);
17 };
18 var s = new Son(‘银角大王‘, 150); //return 我是子类,我叫银角大王, 今年150岁了
19 s.show();

上面的Son类在定义时,使用Father.call来继承Father的实例属性,使用Object.create方法来继承Father的原型,这样就完整的实现了继承,来看一下分析图

Son的实例s,在原型中有自己的show方法,再往上查找Father的原型,还可以看到show的原型,很清晰的层次结构

其实我们也可以不使用Object.create方法,使用Object.setPrototypeOf 方法来代替,达到同样的效果

把之前例子里第13行代码由

Son.prototype = Object.create(Father.prototype); =>
Object.setPrototypeOf(Son.prototype, Father.prototype);

这两行代码的效果是一样的,第二种方法更直观一些,就是把Son.prototype.__proto__ = Father.prototype 这样。

最后一个问题,我们如何才能向C#或者java里那样,在子类型中调用父类的方法呢?比如Son.prototype.show=function(){super.show()}这样

可以使用Object.getPrototypeOf(Son.prototype)方法来获取原型链的上一级,这样就可以获取到Father.prototype对象了,然后调用show()方法

1 Son.prototype.show = function () {
2     Object.getPrototypeOf(Son.prototype).show();
3     console.log(‘我是子类,我叫‘ + this.name + ‘, 今年‘ + this.age + ‘岁了‘);
4 };

但是调用Son的show方法,会log出: 我叫:undefined, 今年undefined岁; 我是子类,我叫银角大王, 今年150岁了

为什么会有undefined?看看刚才我们的f12结构图,Father.prototype中是没有name 和 age 属性的,那么怎么办?使用call方法啊!

下面贴出完整的类继承实现代码:

 1 function Father(name, age){
 2     this.name = name;
 3     this.age = age;
 4 }
 5
 6 Father.prototype.show = function () {
 7     console.log(‘我叫:‘ +this.name+‘, 今年‘+this.age+‘岁‘);
 8 };
 9
10 function Son(name, age){
11     Father.call(this, name, age);
12 }
13 Object.setPrototypeOf(Son.prototype, Father.prototype);
14 Son.prototype.constructor = Son;
15 Son.prototype.$super = Object.getPrototypeOf(Son.prototype);//使用$super属性来指向父类的原型
16 Son.prototype.show = function () {
17     this.$super.show.call(this);
18     console.log(‘我是子类,我叫‘ + this.name + ‘, 今年‘ + this.age + ‘岁了‘);
19 };
20 var s = new Son(‘银角大王‘, 150);
21 s.show();

OK,今天的总结写完了,跟流水账一样,大家凑活看吧

时间: 2024-10-08 13:30:17

es6继承 vs js原生继承(es5)的相关文章

js原生继承之——构造函数式继承实例

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>constructorfunctionInherit</title>    <script type="text/javascript">    //声明父类    function superClass(id){  

js原生继承之——组合式继承实例

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>groupInherit</title>    <script type="text/javascript">    //声明父类    function superClass(name){        this.n

js如何实现继承(js实现继承的五种方式)

js继承有5种实现方式: 1.继承第一种方式:对象冒充 function Parent(username){ this.username = username; this.hello = function(){ alert(this.username); } } function Child(username,password){ //通过以下3行实现将Parent的属性和方法追加到Child中,从而实现继承 //第一步:this.method是作为一个临时的属性,并且指向Parent所指向的对

js - 原型继承和应用

前言:本文大体摘自:https://blog.csdn.net/sysuzhyupeng/article/details/54645430    这位CSDN博主写的十分的好,逻辑性很强.后面 "如何安全的扩展一个内置对象 " 是我添加的.顺便把这位博主的  详解js中extend函数  和  call和apply上手分析  摘抄下来. 原型继承:利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承,这种实现继承的方式,就叫做原型继承. 原型继承是js的一种继承方式,原型继承

ES6内建对象的继承

在ES6之前, JS是无法通过继承的方式创建属于自己的特殊数组的, 也就是说可以使用原型链来继承数组的一些方法, 但是某些返回一个数组的方法返回的值还是一个Array的实例, 例如slice, length等, 还是Array的实例属性, 和当前原型链末尾的函数没什么关系, 只是借用了Array的方法. 1 // 实例: 2 // Array的行为 3 let colors = []; 4 colors[0] = 'red'; 5 console.log(colors.length); // 1

通过寄生组合式继承创建js的异常类

最近项目中在做js的统一的异常处理,需要自定义异常类.理想的设计方案为:自定义一个异常错误类BaseError,继承自Error,然后再自定义若干个系统异常,例如用户取消异常.表单异常.网络异常,继承自BaseError.系统中,根据各个自定义异常做统一的异常处理,例如如果是用户发出取消操作指令,当前调用链则抛出一个用户取消异常,然后由统一异常处理捕获,先判断他是不是继承自BaseError,如果是则再根据事先定义好的处理方案处理. 为啥说这只是理想的设计方案呢?因为es5根本就没有提供js的继

【深入JavaScript】一种JS的继承方法

这些天读了John Resig的<Secrets of JavaScript Ninja>,其中讨论到JS中实现继承的方案,非常有趣,自己探索了一下,形成了笔记,放到这里. 这个方案在Resig的博客上也有,虽然代码略微有点不一致,但核心思想是一样的,请戳 这里 . <html> <head> <title></title> </head> <body> <script type="text/javascr

浅谈JS的继承

JS继承 继承是OO语言中最为人津津乐道的概念,许多OO语言都支持两种方式的继承:接口继承:实现继承. 接口继承:只继承方法签名. 实现继承:继承实际的方法. 由于ES里函数没有签名,所以在ES里面无法实现接口继承,ES只支持实现继承.                                                                                                                                    

JS对象继承的几种方式总结

今天学习了一下js的继承,js中的继承主要分四种,原型继承,构造函数继承,call/apply继承以及es6的extend继承.1.原型继承:原型继承主要利用js对象的prototype引用父类的构造函数来复制父类的方法. //定义一个Person类 function Person(name){ this.name=name; } //打招呼 Person.prototype.sayHello=function(){ alert("Hello,my name is "+this.nam