• JavaScript 类式继承与原型继承


    交叉着写Java和Javascript都有2年多了,今天来总结下自己所了解的Javascript类与继承。

    Javascript本身没有类似Java的面向对象的类与继承术语,但其基于原型对象的思想却可以轻松实现各种类和继承。

    下面来描述实现类的第一种方法,请看例子:

    function People(name, age){
        this.name = name;
        this.age = age;
        this.say = function(){
            console.log('hello, javascript!');
        };
    }
    var people = new People('sky',25);
    people.say();

    从形式上看上去,与面向对象的类几乎一样,this为实例化后的对象自身,name/age为成员变量,say为成员方法,但其内部原理却相差甚远。

    接下来分析其中的不同之处,先看一下代码:

    var people_1 = new People('sky1',21);
    var people_2 = new People('sky2',22);
    people_1.say == people_2.say//false

    按照面向对象语言的特征,表面上看上去people_1/2都有自己的属性name/age,有公共的(占用同一份内存区域)方法say,但在JS中并非如此。

    首先,People自身是一个对象,new People产生了两个对象people_1/2,每个对象都拥有各自的内存空间,即将name/age/say在各自空间都存在一份。

    可通过 people_1.say == people_2.say 验证,结合下图可清楚得出结论,每个对象之间是独立的个体,没有关联关系。

    接下来,结合JS原型概念构造类的第二种方法。原型是JS的核心概念,后续篇章详细描述。

    function People(name,age){
        this.name=name;
        this.age=age;
    }
    
    People.prototype.say = function(){
        console.log('hello, javascript!'); 
    };
    
    var people_1 = new People('sky1',21);
    var people_2 = new People('sky2',22);
    
    people_1.say == people_2.say//true

    通过看到上述代码结果,可得出people_1/2共享成员say,可通过下图分析。这里涉及到了原型链的概念,后面和原型一起阐明。

    关于类的构造就介绍到这。接下来描述实现继承的几种方法。

    先来看第一种,基于类式继承的方式。

    function People(name,age,sex){
        this.name=name;
        this.age=age;
        this.sex=sex;
        this.say=function(){
            console.log('hello,javascript!');
        };
    }
    
    function Man(name,age){
        People.call(this,name,age,'male');
    }
    
    function Woman(name,age){
        People.call(this,name,age,'female');
    }

    var man = new Man('sky-man',21);
    var woman = new Woman('sky-woman',22);
    man.say();
    woman.say();

    这种继承基于第一种类的构造形式,即采用复制的方法实现子类对象对父类成员的继承。

    其中,起复制作用的关键在与People.call(this,...)语句上,意思是使用call方法借用People函数来构造Man对象。

    这里不太好理解,首先要理解call方法如何使用,其次要了解this作用域的概念和使用。关于作用域及作用域链概念也在以后的篇章中阐述。

    总之,这里的意义是将People对象的属性复制到Man对象上。

    我们看下这里的图形描述:

    很显然man/woman都继承了People的成员变量,但其采用的是复制的方法,对象之间并没有建立真正的继承。

    接下来将基于第二种构造类的方法来介绍第二种构造类的形式,即继承依赖原型。直接看一下代码:

    function People(name,age,sex){
        this.name=name;
        this.age=age;
        this.sex=sex;
    }
    
    People.prototype.say=function(){
        console.log('hello,javascript!');
    }
    
    function Man(name,age){
        People.call(this,name,age,'male');
    }
    
    Man.prototype = Object.create(People.prototype);
    
    function Woman(name,age){
        People.call(this,name,age,'female');
    }
    
    Woman.prototype = Object.create(People.prototype);

    上面的代码可能已经引入一些JS原理层面的东西,还是先用图来展示:

    上图中引入几个比较JS原理的东西,prototype/constructor/__proto__,其中前两者是JS标准中存在的,

    而__proto__是标准中未暴露的,该名称采用chrome暴露的属性名。

    其中prototype是原型函数,每个函数中都存在;constructor是构造器,每个对象都存在;__proto__是原型对象,每个对象都存在。

    此处先介绍到这,后期将根据ECMAScript标准详细介绍几者之间的关系。

    通过上面的线条可以了解每个对象之间的关系,以及原型链在其中所起的作用。

    可以看出,第二种继承方法是基于原型的,虽然成员是采用复制的方式,但保证了方法的继承性。这与传统面向对象类继承意义上才是一致的。

    通过上面的类的构造和继承方式,我们对Javascript原型继承有一定了解。那么如果要实现内部成员,内部方法,该如何实现呢?

    疑问将在下个篇章解答。

  • 相关阅读:
    Java Native Method
    SQL语句优化
    Ibatis的环境搭建以及遇到的问题解决
    Java 构建器
    SpringMVC自定义视图 Excel视图和PDF视图
    java 枚举的常见使用方法
    mysql 根据某些字段之和排序
    MFC The Screen Flickers When The Image Zoomed
    How To Debug Qmake Pro File
    Gcc And MakeFile Level1
  • 原文地址:https://www.cnblogs.com/tesky0125/p/4619556.html
Copyright © 2020-2023  润新知