zoukankan      html  css  js  c++  java
  • 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,今天的总结写完了,跟流水账一样,大家凑活看吧

  • 相关阅读:
    什么是Servlet?
    哪种情况下用哪种域对象
    相对于Statement,PreparedStatement的优点是什么?
    JDBC的PreparedStatement是什么?
    execute,executeQuery,executeUpdate的区别是什么?
    什么是JDBC,在上面时候会用到它?
    ArrayList、LinkedList、Vector 的区别。
    int 和 Integer 有什么区别
    Java 为每个原始类型提供了哪些包装类型
    什么是JDBC,在上面时候会用到它?
  • 原文地址:https://www.cnblogs.com/chengzi/p/5623280.html
Copyright © 2011-2022 走看看