JS深入面向对象

ppgo8 于 2023-05-01 发布

深入面向对象

熟练理解:原型对象、对象原型

编程思想

面向过程编程

面向对象编程(oop)

二者对比

image-20230501132820261

构造函数

image-20230501133617924


总结

  1. JS实现面向对象通过什么实现?
    • 构造函数
  2. 构造函数存在什么问题?
    • 复杂数据类型会,浪费内存

原型

各个对象在构造函数中的方法一样,重复在内存中实现,很浪费,该怎么解决?可以只生成一份吗?(构造函数存储的数据不一样,只是数据属性名称一样)

原型可以解决构造函数浪费内存的问题。

原型

目标:能够利用原型对象实现方法共享


小结

  1. 原型是什么?

    • 原型是构造函数的一个属性,是对象类型

    • 一个对象,也称为prototype为原型对象

  2. 原型的作用是什么?

    • 共享方法
    • 可以把那些不变的方法,直接定义在prototype对象上
  3. 构造函数和原型里的this指向谁?

    • 都指向实例化对象

      image-20230503085709116

补充:数组拓展

// 展开运算符
console.log(...[1, 2, 3]);        // 展开得到数字类型
console.log([1, 2, 3].join(',')); // 字符类型

需求:

const arr = [1, 2, 3]

/*1. 最大值 */
Array.prototype.max = function (arr) {
    // 返回undefined,没有接受到参数值:因为在arr.max()调用时,没在max()里面写参数。                                   // 如果在()里面写arr参数,那么就很重复,因为前面调用的时候已经写过了,解决方法见下。
    console.log(arr)       
    return Math.max(...arr)
}

// 不想重复写arr作为参数的方法,巧妙利用this
Array.prototype.max = function () {
    // 巧妙利用this
    return Math.max(...this) // this指向调用者
}
const max = arr.max()
console.log(max)
// 实现求和
Array.prototype.sum = function () {
      return this.reduce((prev,item) => prev+item, 0)
}
console.log(arr.sum())

constructor属性

在哪里?每个原型对象里面都有一个constructor属性

作用:该属性指向该原型对象的构造函数。简单理解:指向父亲

image-20230503094753670

使用场景:


小结

  1. constructor属性的作用是什么?

    指向该原型对象的构造函数(在对prototype对象重新赋值的时候)

对象原型

https://www.bilibili.com/video/BV1Y84y1L7Nn/?p=181&spm_id_from=pageDriver&vd_source=dde2f4dd432156027fedf9b1734ba705 有个笔记和案例没做

为什么实例对象可以访问原型对象中的方法?

image-20230503100904045

构造函数、原型对象、对象原型之间的关系

image-20230503101911642


小结

  1. prototype是什么?来自哪里?
    • 原型(原型对象)
    • 来自于构造函数
  2. constructor属性在哪里?作用?
    • 在prototype对象和对象原型__proto__中
    • 都指向创建实例对象/原型的构造函数
  3. __proto__属性在哪里?指向谁?
    • 在实例对象中
    • 指向原型对象prototype

原型继承

基础知识

 <script>
	const Person ={
	    eyes:2,
	    head:1
	}
	// 构造函数,通过继承实现
	function Woman(){}
	function Man(){}
	
	// 女人继承
	Woman.prototype = Person
	// prototype重新指向构造函数
	Woman.prototype.constructor = Woman 
	
	// 给女人添加专有方法,生孩子;挂在woman的原型上,因为每个woman都有
	Woman.prototype.baby = function (){
	    console.log('宝贝')
	}
	const red = new Woman()
	console.log(red)
	console.log(Woman.prototype)
	
	// 男人继承
	Man.prototype = Person
	Man.prototype.constructor = Man
	
	const pink = new Man()
	console.log(pink)
	console.log(Man.prototype)
</script>

问题

进行了新的操作,给女人添加专有方法,生孩子

// 给女人添加专有方法,生孩子;挂在woman的原型上,因为每个woman都有
Woman.prototype.baby = function (){
    console.log('宝贝')
}
// 问题:男人和女人的实例化对象均有baby的方法
// 原因:男人和女人的portotype原型对象相等,二者指向同一个对象
Woman.prototype = Person
Man.prototype = Person

image-20230503111443156

解决方法

需求:男人和女人不要使用同一个对象,但是不同对象里面包含相同的属性和方法

答案:构造函数

new每次都会创建一个新的对象

// 抽取方法更正:要求:结构一样但是对象不一样
function Person() {
    this.eyes = 2,
    this.head = 1
}

// 构造函数,通过继承实现
function Woman() {
}
function Man() {
}

// 女人继承
Woman.prototype = new Person
// prototype重新指向构造函数
Woman.prototype.constructor = Woman

// 给女人添加专有方法,生孩子;挂在woman的原型上,因为每个woman都有
Woman.prototype.baby = function () {
    console.log('宝贝')
}


// 男人继承
Man.prototype = new Person
Man.prototype.constructor = Man

小结

  1. 继承的方法

    子类的原型 = new 父类
    子类.prototype = new 父类
    

原型链

基础知识

每个对象都有__proto__,对象原型。

对象原型

image-20230503114351044

什么是原型链?

原型链是一种查找规则

  1. 当访问一个对象的属性(或方法)时,首先查找这个对象自身有没有该属性
  2. 如果没有,就查找它的原型(也就是__proto__指向的prototype原型对象)
  3. 如果还没有,就查找原型对象的原型
  4. 依次类推一一直找到Object位置(null

__proto__对象原型的意义在于为对象成员查找机制提供一个方向,或者一条线路

可以使用instanceof运算符用于检测构造函数的prototype的属性是否出现在某个实例对象的原型链上。

instanceof运算符

console.log(ldh instanceof Person)
console.log(ldh instanceof Object)
console.log(ldh instanceof Array)
console.log([1,2,3] instanceof Array)

综合案例

https://www.bilibili.com/video/BV1Y84y1L7Nn/?p=184&spm_id_from=pageDriver&vd_source=dde2f4dd432156027fedf9b1734ba705