概念
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