zoukankan      html  css  js  c++  java
  • javascript面向对象

    1.类与实例

    1.1 类的声明

    function Animal() {
        this.name = 'name';
    }

    1.2 ES6中类的声明

    class Animal2{
        constructor() {
            this.name = name;
        }
    }

    1.3 类的实例化

    new Animal(); //没有参数的话,括号可以不要

    2.类与继承

    2.1 借助构造函数实现继承

    function Parent1() {
        this.name = 'parent1';
    }
    function Child1() {
        Parent1.call(this); 
        this.type = 'child1';
    }

    缺点:只实现了部分继承,继承不到父类原型上的方法。

    测试代码如下,运行时会报错。child1没有继承到父级原型上的方法。

    function Parent1() {
        this.name = 'parent1';
    }
    Parent1.prototype.say = function() {}
    function Child1() {
        Parent1.call(this); 
        this.type = 'child1';
    }
    console.log(new Child1(), new Child1().say());

    2.2 借助原型链实现继承

    这种方式可以解决第一种方法无法继承父级对象原型上方法的问题。

    function Parent2() {
        this.name = 'parent2';
    }
    function Child2() {
        this.type = 'child2';
    }
    Child2.prototype = new Parent2();
    缺点:改一个对象属性,另一个也跟着改变。原型对象是共用的。
    function Parent2() {
        this.name = 'parent2';
        this.play = [1, 2, 3];
    }
    function Child2() {
        this.type = 'child2';
    }
    Child2.prototype = new Parent2();
    var s1 = new Child2();
    var s2 = new Child2();
    s1.play.push(4);
    console.log(s1.play, s2.play); //[1,2,3,4] [1,2,3,4]

    2.3 组合方式

    方案一二的结合版,可以解决部分继承和原型对象共用的问题。是最通用的方式。

    function Parent3() {
        this.name = 'Parent3';
    }
    function Child3() {
        Parent3.call(this);
        this.type = 'child3';
    }
    Child3.prototype = new Parent3();
    缺点:父类构造函数执行了两次,是没有必要的。
    function Parent3() {
        this.name = 'Parent3';
        this.play = [1,2,3];
    }
    function Child3() {
        Parent3.call(this);
        this.type = 'child3';
    }
    Child3.prototype = new Parent3();
    var s3 = new Child3();
    var s4 = new Child3();
    s3.play.push(4);
    console.log(s3.play, s4.play);

    2.4 组合继承的优化一

    优化:父类构造函数只执行了一次

    function Parent4() {
        this.name = 'Parent4';
    }
    function Child4() {
        Parent4.call(this);
        this.type = 'child4';
    }
    Child4.prototype =Parent4.prototype;

    缺点:不能区分是直接由parent4实例化的还是child4实例化的。

    用instanceof判断:

    function Parent4() {
        this.name = 'Parent4';
    }
    function Child4() {
        Parent4.call(this);
        this.type = 'child4';
    }
    Child4.prototype =Parent4.prototype;
    var s4 = new Child4();
    var s5 = new Child4();
    console.log(s4 instanceof Child4, s4 instanceof Parent4); //true true

    用constructor构造器判断,它是Parent4的实例。这显然不是我们想要的。此时不难判看出,上一个组合方法中也会是这样的结果。它们直接拿的是父类的实例,它们没有自己的constructor,它的constructor是从父类实例继承的,也就是原型链的上一级拿来的,所以是父类的constructor。

    console.log(s4.constructor);  // Parent4对象

    2.5 组合继承优化二

    function Parent5() {
        this.name = 'Parent5';
    }
    function Child5() {
        Parent5.call(this);
        this.type = 'child5';
    }
    Child5.prototype =Object.create(Parent5.prototype);
    Child5.prototype.constructor = Child5;

    通过创建中间对象的方法,就把两个原型对象区分开,这个中间对象还具备一个特性,它的原型对象是父类的原型对象。这样在原型链上就连起来了,通过再给child5这个原型对象上的constructor作修改,那么就能正确区分父类和子类构造函数了。

    至此,问题就全部解决了。

    var s7 = new Child5();
    console.log(s7 instanceof Child5, s7 instanceof Parent5);
    console.log(s7.constructor);

    控制台打印结果:

  • 相关阅读:
    二分查找:思路很简单,细节是魔鬼
    今天遇到了 X-Y PROBLEM
    《工匠精神》读书笔记
    养成好的职业习惯
    php xdebug 调试
    Dockerfile的常见命令
    docker制作镜像
    脱坑笔记
    Java中代理
    2、遇到多个构造器参数的时候要考虑使用构建器
  • 原文地址:https://www.cnblogs.com/PeriHe/p/8568573.html
Copyright © 2011-2022 走看看