• 面向对象JS ES5/ES6 类的书写 继承的实现 new关键字执行 this指向 原型链


    一 、什么是面向对象?

      面向对象(Object Oriented),简写OO,是一种软件开发方法。
      面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
      面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。
      面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。

    编程范式

      一般可以分为两种:

        声明式,告诉计算机应该做什么,但不指定具体要怎么做。如:html,css等

        命令式,关注计算机执行的步骤,即一步一步告诉计算机先做什么再做什么。如:js,c++,java,c#,python等

      其中命令式编程又可以为两类

        面向过程:

        将我们要解决问题所需要的步骤分析出来,然后用函数把这些步骤一步一步实现(有序步骤),关注细节。

        面向对象:

        将问题中的对象抽象出来,既把构成问题的事物分解成各个对象,而解决问题的不是一个个过程化的步骤,

        而是利用对象描述、处理“问题”的行为集合(离不开面向过程)。

    二、面向对象的基本概念

    1、对象

      对象的含义是指具体的某一个事物,即在现实生活中能够看得见摸得着的事物,有句话叫做:万物皆对象。

      对象是类的具体实例,对象的抽象是类。

    2、类

      类是具有相同特性(数据元素)和行为(功能)的对象的抽象,代表一类事物的抽象描述。

      在代码中:类好比是一个模板,可以批量生产。

      类是对象的抽象,类的具体化就是对象。


      类的实现

      原本JS不支持面向对象(oo),所以在ES5用函数模拟出类,在ES6时加入语法糖,书写起来更加清晰、更像面向对象编程的语法。

      类的本质是函数:构造函数+全局公共区域 prototype。

    ES5

    //混合模式:构造函数模式+原型模式
    function Person(name, age) {//构造函数模式
        this.name = name;  /*属性*/
        this.age = age;
        this.study = function () {
            console.log(this.name + '在运动');
        }
    }
    
    //原型模式 prototype,原型链上面的属性会被实例对象共享
    Person.prototype.sex = "男";//共有的属性
    Person.prototype.exercise = function () {//共有的函数
        console.log(this.name + '在锻炼');
    }
    
    //类的静态属性和方法不会被实例对象共享
    Person.num = 11234;//定义静态属性
    Person.printNum = function () {//定义静态方法
        console.log(this.num);
    }//注:函数也是一个对象,所谓的静态属性方法,本质就是给名为Person的对象添加了属性和方法
    
    var stu = new Person('张三', 20);
    console.log(stu);//Person { name: '张三', age: 20, study: [Function] }
    console.log(stu.sex);//
    stu.study();//调用自带方法 => 张三在运动
    stu.exercise(); //调用原型方法 => 张三在锻炼
    
    console.log(Person.num);//11234    静态属性和方法 通过 类名.方法(属性名) 调用或访问
    console.log(stu.num);//undefined    实例对象不能使用
    Person.printNum();//11234
    stu.printNum();//报错 stu.printNum is not a function


    ES6

    class Person {
        constructor(name, age) {//构造函数
            this.name = name;  /*属性*/
            this.age = age;
            this.sex = "男";
            this.study = function () {
                console.log(this.name + '在运动');
            }
        }
    
        static num = 11234;//定义静态属性 
        static printNum() {//定义静态方法
            console.log(this.num);
        }
        exercise() {//共有的函数
            console.log(this.name + '在锻炼');
        }
    }
    var stu = new Person('张三', 20);
    console.log(stu);//Person { name: '张三', age: 20, sex: '男', study: [Function] }
    console.log(stu.sex);//
    stu.study();//张三在运动
    stu.exercise(); //张三在锻炼
    
    console.log(Person.num);//11234    
    console.log(stu.num);//undefined    
    Person.printNum();//11234
    stu.printNum();//报错 stu.printNum is not a function

    注:两种方式都能成功的声明一个Person类,现在一般就用ES6方式,但是其实内部是用ES5的方式运行的,ES6方式相当于一个语法糖。

      关于new

        每次使用new关键字会执行的步骤:

          1、创建一个空的新对象,作为将要返回的对象实例
              var obj = {};
          2、将该对象的__proto__(隐式原型)指向创建该对象的类的原型对象
              //假设类叫做 A
              obj.__proto__ = A.prototype;
          3、将构造函数环境中的this,指向该对象
              相当于:this = obj;//意识到位,代码这样写是错误的
          4、执行构造函数中的代码,并返回刚刚创建的新对象

     注:class 定义的类,必须使用new关键字调用,不然会报错,

      new关键字总是返回一个对象,如果new 普通函数,会返回一个空对象。

      关于构造函数constructor

        
      constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。
      在类中必须存在构造函数,可以不书写,会默认补一个空构造constructor{}


      返回值
        构造函数也有返回值,默认返回实例对象(即this),可以更改,若改为基本数据类型的返回值,则不影响函数。
        若改为复杂数据类型的返回值,则会直接将该返回值直接返回,会导致返回值不再是原来类的实例对象,

    三、面向对象三大特征


    1、封装

      隐藏内部细节,不暴露在外面;做到信息的隐藏,不关心具体怎样实现的,只需要知道能达到效果就行了。

      具体表现形式:
          函数    是对于算法的封装
          类    是对于属性和方法的封装

    2、继承

      子类继承父类的所有属性和方法,并且扩展自己的属性和行为。

      类与类之间的关系:is a(是一个)  例如:学生——>人类

      实现

     

    function Student(){
        Person.call(this);    //对象冒充实现继承 对象冒充可以继承构造函数里面的属性和方法   但是没法继承原型链上面的属性和方法
    }
    //原型链实现继承  原型链实现继承:可以继承构造函数里面的属性和方法 也可以继承原型链上面的属性和方法
    Student.prototype = Object.assigin(Person.prototype);   //与拷贝类似,但不同
    //Student.prototype=new Person();   //这种方法功能是能实现,但是太矬了
    // Student.prototype = Object.create(Person.prototype); //没有将create的储存起来,只是利用原型链找到有属性的父类

    改变this指向的三个函数实例方法

    var name = 99;
    function foo(a, b) {
        console.log(this.name, a, b);//this本来指向全局的 name=99
    }
    let zs = {
        name: "zs"
    }
    let ls = {
        name: "ls"
    }
    //call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数第一个参数(对象)为指向。
    foo.call(ls, 1, 2);//ls 1 2
    //apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数
    foo.apply(zs, [2, 3]);//zs 2 3
    //bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。这个要主动调用
    let bar = foo.bind(zs);
    bar(3,4);//zs 3 4


      ES6

    // 图形祖宗
            class Graph {
                constructor(color, top, left) {
                    this.color = color;
                    this.top = top;
                    this.left = left;
                    this.node = null;
                }
                creatNode() { }
                addNode() {
                    document.body.appendChild(this.node);
                }
            }
    // 矩形
            class Rectangle extends Graph {
                constructor(color, top, left, lengthX, lengthY) {
                    super(color, top, left);
                    this.lengthX = lengthX;
                    this.lengthY = lengthY;
                }
                creatNode() {
                    this.node = document.createElement(`div`);
                    this.node.style.position = "absolute";
                    this.node.style.background = this.color;
                    this.node.style.top = this.top + "px";
                    this.node.style.left = this.left + "px";
                    this.node.style.width = this.lengthX + "px";
                    this.node.style.height = this.lengthY + "px";
                }
            }

      extends 扩展  从子类,扩展到父类  即继承父类

      super 超类  继承父类  用于调用父亲的构造,必须与extends关键字一起使用,且只能在构造函数中所有的this之前书写


    3、多态


    方法(行为)  相同的行为不同的实现  传的参数不一样,决定了实现方法不一样


    代码中的多态:  
        重载  参数的不同,实现不同  js自带,因为js没有严格的指定参数的个数类型


        重写  父亲的行为,儿子重写一个覆盖了

     

    四、this和原型对象

    this指向问题

    1、箭头函数中,没有自己的this,它借用声明箭头函数处(环境中的)的this(就固定这个值)

    2、谁调用,指向谁

    3、事件监听函数中,this指向,绑定监听函数的那一个元素节点(谁绑,指向谁)

    4、当一个函数没有被其他对象调用时,(普通调用),this指向全局对象(严格模式下面是undefined)

    5、在执行构造函数时(new),this指向新创建的对象

     

    原型对象


    规则:

    所有function创建的对象,都叫做函数对象(函数)

    所有函数对象上都有一个原型对象,prototype

    所有对象上都有一个隐式原型对象,__proto__,指向创建该对象的构造函数的原型对象

    所有原型对象上都有一个constructor对象,指向该原型对象所在的构造函数本身

    或者这样说:

    对象可以分为函数对象(所有直接通过function创建的对象)和一般对象(其他对象),所有的对象在创建时,都会创建一个对应的原型对象

    函数对象的原型对象为:函数.prototype,函数.prototype上都有一个constructor对象,指向该原型对象所在的构造函数本身

    一般对象的原型对象被称为隐式(和函数对象的原型对象相区分)原型对象: 对象.__proto__,指向创建该对象的构造函数的原型对象


    原型链:

    一个对象通过自身的__proto__,一直向上链接,直到null,所构成的的链条,就是原型链


    原型链作用:用来找属性

    当一个对象在访问自身某个属性时,会先在自己身上找,没有找到就通过原型链(__proto__),层层向上找,直到找完为止

    若找完整个原型链都没有找到,那么该属性的值就是,undefind。

     
     
  • 相关阅读:
    Python 命令模式和交互模式
    Python自带IDE设置字体
    Python2.7和3.7区别
    Kubernetes1.91(K8s)安装部署过程(八)-- kubernetes-dashboard安装
    Kubernetes1.91(K8s)安装部署过程(七)--coredns安装
    nginx 设置自签名证书以及设置网址http强制转https访问
    Kubernetes1.91(K8s)安装部署过程(六)--node节点部署
    VMware安装VMware tool是 遇到The path "" is not a valid path to the 3.10.0-693.el7.x86_64 kernel headers.
    第三方git pull免密码更新
    Kubernetes1.91(K8s)安装部署过程(五)--安装flannel网络插件
  • 原文地址:https://www.cnblogs.com/jiayouba/p/12004285.html
Copyright © 2020-2023  润新知