JavaScript面向对象

概念

  • OO:Object Oriented(面向对象,详细概念见区别)

  • OOP(Program)面向对象编程

  • OOD(Design)面向对象设计

  • OOA(Analysis)

区别

  • 面向过程

    • 关注方法步骤
    • 在分析问题时,提取出解决问题的方法和步骤,然后通过函数一步步实现,并依次调用
  • 面向对象(实质是对面向过程的进一步抽象)

    • 关注对象本身
    • 把要解决的问题中的数据和方法组织为一个整体(对象)来看待,是我们对现实事物的抽象。
  • 注意:

    • 面向过程和面向对象这两种编程方式,都是用来编写程序,解决我们实际需求以及问题的。
    • 二者示例对比:开车
      • 面向过程的开车:先打开车门,上车,系好安全带,把车钥匙插入,点火。。。。
      • 面向对象的开车:找一个司机,开车

基本构成

  • 对象(具体)

    • 问题域中关注的具体的某一事物(对象因关注而产生)
  • (抽象)

    • 具有相同性质和行为的一组对象的抽象(分类)
    • 在代码中起“模具”作用
    • 大驼峰命名是类的标志(注意:并不是说只要大驼峰命名就是类,或者不使用大驼峰命名就不是类了,只是一种标志,便于开发者区分)
  • 关系:类是对象的抽象,对象是类的实例。

    • 所有对象都是类创建的,所以对象又称为实例对象。用类创建对象的过程叫做实例化。

ES6语法糖

//ES6 class----模版
        class Person {
            constructor(name, age, gender) {
                this.name = name;
                this.age = age;
                this.gender = gender;
            }
            // name = "张三";
            // age = "18";
            //gender="男";
            eat() {
                console.log(this.name);
            }
        }
        // 生成对象----模版---->实例
        let p1 = new Person("张三",18,"男");
        let p2 = new Person("里斯",13,"女");
        let p3 = new Person("王五",17,"男");
  • 只能使用new关键字调用,不能像普通函数那样调用,会报错。
  • class声明的类有暂时性死区,不能在声明前调用。

ES5原理分析

//将ES6语法糖还原为ES5原理
function Person {//构造函数,内部写属性
	this.name = name;
	this.age = age;
	this.gender = gender;
}

//方法放在构造函数身上的原型对象prototype上
Person.prototype.eat=function(){
    console.log(this.name);
}

// 生成对象----模版---->实例
let p1 = new Person("张三",18,"男");
let p2 = new Person("里斯",13,"女");
let p3 = new Person("王五",17,"男");
  • typeOf类-------->"function"
    • 说明类就是函数(构造函数)
    • 如何判断一个函数是普通函数还是类(构造函数),本质上是由调用函数的形式决定
      • 普通调用Person()
      • 使用new关键字进行调用new Person()
  • 属性和方法
    • 实例属性(私有)
      • 在构造函数内部以this.xxx=xxx;的方式进行创建
    • 公有属性
    • 方法
      • 公有属性和方法,统一放在类.prototype这个原型对象上,这里就是公共区域。
  • 类是通过JS函数模拟出来的,JS原本就不是面向对象的语言,是因为有了大量的需求才模拟出了类。
  • 使用new关键字调用时,究竟发生了什么
    • 创建一个新对象
    • 将新对象身上的__proto__指向创建该对象的构造函数身上的prototype
    • 将构造函数(类)内部的this指向刚刚创建的实例对象
    • 执行代码,将新对象作为返回值返回
  • 注意:
    • class声明的类有暂时性死区,不可在声明前使用。

补充知识

Object上的方法
  • Object.assign(),整合函数
this指向
  • 箭头函数没有自己的arguments和this,this的指向问题,取决于它所处的环境。
    • 由于箭头函数没有this,所以不能作为构造函数。
    • 箭头函数的this一旦确定下来,就不会再改变了。
  • 事件监听器中的this,指向绑定事件的元素节点。
  • 构造函数内部的this,指向刚刚创建的实例对象。
  • 普通函数调用时,this一般指向window,但在严格模式下指向undefined。
    • 严格模式:就是在某个执行上下文的第一句写“use strict”,就是指定该环境中使用严格模式。
  • 谁调用指向谁。
函数上的方法(方法借用)
  • 立即执行
    • call
    • apply
  • 稍后执行
    • bind
包装类
  • 目的:
  • 有哪些
    • String
    • Number
    • Boolean
  • 特点:自动装箱,自动拆箱
toString和valueOf

三大特征:

封装(encapsulation)
  • 将数据和方法捆绑在一起(如函数、类(对象))就实现了“装”,将其私有化只能自己使用就是“封”(可利用闭包实现)。
继承(inheritance)
  • 类与类之间的关系。子类继承父类所有的属性和方法,并且拥有自己独特的属性和方法。(即满足xxx是xxx的关系)
多态(polymorphism)
  • 不同东西,对同一件事(行为)的表现形式不同。

ES6继承(语法糖)

关键字:extendes和super
  • extends

    • 表达继承关系,书写在要声明的类后面,后面是要继承的父类。
    • extends需与super搭配使用,如果写了构造函数,里面必须调用super(),否则会保存;如果没不写构造,JS会自动为我们写一个空的构造器,并自动调super();
  • super

    • super() 方法放在子类的构造函数中,只能调用一次,且必须放在this和return之前(最好写在构造函数第一行)。如果父类需要传参,小括号内为传入的实参。
class Student extends Person{
    constructor(){
        super();//可传参,实参
        this.xxx=xxx;
        ......
    }
}

原型

对象分类
  • 函数对象(typeOf---->”function“)
  • 其他对象(typeOf---->”object“)
规则
  • 除箭头函数外,所有函数对象身上都有一个原型对象(prototype)。
  • 所有对象身上都有一个隐式原型对象(__proto__,一个引用),它指向创建该对象的构造函数身上的原型对象。
  • 原型对象通常是一个普通对象,说明它是Object类的实例,作为对象它身上也有__proto__这个隐式原型对象,指向创建它的构造函数Object身上的原型对象。
  • 所有原型对象(prototype)上都有一个constructor引用,指向该原型对象所在的构造函数。
原型链
  • 实例对象,通过__proto__不断的反复向上寻找,会形成一个链条,这个链条是用来找属性的,如果在链条的头部(自己身上)没有找到,会在下一个节点继续找,直到找完整个链条。如果找完整个链条都没有找到,则结果为undefined。
  • 方法是特殊的属性,当一个属性的值为函数的时候,它就变成了方法。
  • 原型链的出口(顶端)是Object.prototype,它身上的__proto__指向null。
  • 原型链中,如果各原型对象上有相同的属性,那么前面原型对象的这个属性会覆盖后面的(多态的一种表现)
  • 区别:作用域链------>找变量

继承原理(ES5)

  • 混合继承=方法借用(继承属性)+原型继承(将父类的原型插入子类的原型链)
    • 方法借用
      • call
      • apply
      • bind
    • 原型继承
      • Object.create()
function Super(name, age) {//父类,超类
     this.name = name;
     this.age = age;
}
Object.assign(Super.prototype, {
     sleep() {
        console.log(`${this.name} is sleeping!`);
     }
})

//子类
function Sub(name, age, gender) {
     Super.call(this, name, age);
    //以调用父类构造函数的形式,得到执行结果,将this绑定为当前的实例对象
    //普通调用时,this的指向window而不是当前实例对象,所以使用方法借用,绑定this的指向
     this.gender = gender;
}
//原型继承(插入父类的原型链,如果父类在子类的原型链上,那么子类及其实例对象都可以通过原型链找到父类身上方法)
// 父类原型插入的位置,实例对象和子类之间不可,因为实例对象必须指向创建它的类的原型对象;Obj原型和null之间不可,规定Obj.prototype指向null.只能在子类原型和Obj原型之间插入
。
Sub.prototype = Object.create(Super.prototype);//以父类的prototype为原型,创建一个空对象,替换子类的prototype
Sub.prototype.constructor = Sub;//由于空对象身上没有constructor引用,赋值
//自己的方法
Object.assign(Sub.prototype, {
     eat() {
         console.log(`${this.name} is eating!`);
     }
});
let sub1 = new Sub("zs", 18, "male");
// sub1.constructor===>fn Sub//sub1通过自己身上的__proto__指向创建它的类的原型对象 //Sub.prototype,prototype身上有它所在的构造函数的引用constructor
//sub1.__proto__.constructor====>fn Sub

多态

  • 重载:JS自带,传入不同的参数,实现效果不同(如if...else if语句)
  • 重写(覆盖):继承并覆盖父类的方法

类的判断方法

  • instanceof
    • 作用:判断复杂数据类型的类型(是哪个类创建的)
    • 语法:要判断的对象 instanceof 类------->true/false
    • 原理:通过原型链来实现判断(即在该对象原型链上所有经过的类都会判断为true,并不是只要它的父类)
  • 区别:typeof------>判断基本数据类型的类型

ES6 不常用语法

属性的定义方法

  • 已知的定义方法

    let person={
    	name:"zs"
    }//声明式
    
    person.age=18;//直接赋值
    
  • Object.defineProperty()

数据类型:

  • 为什么要进行复杂数据类型判断
    • 传参时传入对象
    • 判断传入的对象到底是什么再决定代码如何执行

JS中

  • 基本数据类型6种(number、string、boolean、undefined、null、symbol)

    • typeof判断基本数据类型的类型
  • 复杂数据类型1种(object)

    • 但是有无数个类(object是他们的顶层表现)
    • typeof复杂数据类型:object、function
    • instanceof判断当前对象是由哪个类创建的
  • JS是弱类型语言:声明变量时,没有定义变量的数据类型,而是根据赋给变量的值的类型来决定它的数据类型。

    • 缺点:由于不知道声明变量要存储的数据类型,尽可能分配到使所有数据类型都能存放下的内存,会造成内存浪费,降低性能。
    • 优点:程序员友好型,不容易报错
  • 其他强类型语言:C,C++,Java等

    • 声明变量时就规定了变量存储的数据类型,只能存储相应类型的数据,否则会报错
    • 优点:根据不同的数据类型,给变量分配不同的内存,精细化内存管理,提高代码性能
    • 缺点:对程序员不友好,需要记忆大量内容,容易报错
  • 抛出错误

    • JS中错误也是个对象
    • throw new Error(".........")
    try{
        throw new Error(".........")
    }catch(e){
        console.log(e);//e就是try里面抓住的错误
    }finally{
        
    }
    //三个一起用,类似于if...else的关系
    
  • JS中万物皆对象

原文地址:https://www.cnblogs.com/Lotus3904/p/12500331.html