05 Web全栈 面向对象编程/原型链/继承

面向对象编程是一种编程范式,关注于对象和它们的行为。它包含封装、继承和多态等核心特性。在JavaScript中,这些特性体现在对象、构造函数、原型链以及不同的继承策略,如原型链继承、构造函数继承和组合继承等。文章还讨论了为何要在原型链上添加属性和方法,以及如何通过`Object.create`实现继承,同时提到了ES6的类继承。
摘要由CSDN通过智能技术生成

什么是面向对象编程

编程思想
面向过程:关注的是动词,分析出解决问题所需要的所有步骤,针对所有步一一实现一些函数,按照顺序来调用函数
面向对象:关注的是主谓,把构成这个问题的事务,拆解成一个个对象,这一个个对象是为了描述这个对象在当前问题中的各种行为方式

面向对象的特性

封装:让使用对象的人不用去考虑内部的实现,对象对外暴露出一些api,提供给使用方使用。
继承:为了代码的复用,从父类继承他允许继承的属性和方法
多态:不同的对象作用于同一个操作,然后产生不同的结果。多态的思想实际上把“想做什么”和“谁去做”这两者分离开。

面向对象特性的表现

五子棋为例:
面向过程:开局 -> 下白棋 -> 判断胜负 -> 下黑棋 -> 判断胜负
面向对象:棋盘、玩家(黑方,白方)

什么场景下适合面向对象编程

面向过程:简单的场景下,协同人员较少
面向对象:中型或者大型项目,协同人员较多,迭代频繁。

JS中的面向对象

方法:
属性

JS中的一些内置对象

// Array Date Function RegExp

// 多态
[].toString()
{}.toString()

// 继承
const o = new Object()
o.toString()

// 封装
const date = new Date()
date.getTime()

JS 中怎么创建对象

// 普通方法
const player = new Object()
player.color = 'red'
player.start = function () {
	console.log('player')
}

// 工厂模式 缺陷:无法判断类型
function CreatePlayer (color) {
	const player = new Object()
	player.color = color
	player.start = function () {
		console.log('player')
	}
	return player
}

// 构造函数和实例 缺陷:每生成一个实例,构造函数内部的方法都会重新开辟一块内容
function Player (color) {
	this.color = color
	this.start = function () {}
}
const p1 = new Player('red')
console.log(p1.constructor) // [Function: Player]

// 原型 方法定义在原型上
function Player (color) {
	this.color = color
}
Player.prototype.start = function () {}

// 静态属性 提供给构造函数调用的属性

为什么要在原型链上添加属性或者方法

在构造函数内通过this添加方法的话,每生成一个对象,都会重新开辟一块内存空间。造成内存浪费。prototype的方式,可以多个对象共用一块空间

怎么找到一个原型对象

function Player (color) {
	this.color = color
	this.start = function () {}
}
const p1 = new Player('red')
p1.__proto__  
=== Player.prototype
=== Object.getPrototypeOf(p1) // 原型对象

p1.__proto__.constructor === Player 

new 关键字到底做了什么

  1. 创建一个空对象p
  2. 将p的__proto__ 指向构造函数的prototype
  3. 将this指向p
  4. 返回这个对象p
    4.1. 构造函数未return,返回p
    4.2. 构造函数 return this 返回对象p
    4.3. 构造函数return基本数据类型,返回对象p
    4.4. 构造函数return对象类型 返回改对象
function myNew () {
	let o = new Object()
	let FunctionConstructor = [].shift.call(arguments)
	o.__proto__ = FunctionConstructor.prototype
	let resultObj = FunctionConstructor.apply(o, arguments)
	return typeof resultObj === 'object' ? resultObj : o
}

原型链是什么

__ proto__ 连起来的链 最终值是null

function Player() {}
Player.prototype.name = 'player'
const p1 = new Player()
console.log(p1.name) // player
p1.name = 'p1'
console.log(p1.name) // p1

继承

原型链继承

function Parent () {
	this.name = 'parent'
	this.actions = ['sing', 'jump', 'rap']
}
function Child () {}
Child.prototype = new Parent()
Child.prototype.constructor = Child

// 问题1 如果父类有引用类型的属性,其中一个实例改变了该属性 所有实例该属性都会改变
// 问题2 无法传参给父类

构造函数继承

function Parent (name) {
	this.name = name
	this.actions = ['sing', 'jump', 'rap']
	this.eat = function () {}
}
function Child () {
	Parent.apply(this, arguments)
}
// 缺点 浪费内存

组合继承
结合原型链继承和构造函数继承

function Parent (name) {
	this.name = name
	this.actions = ['sing', 'jump', 'rap']
}
Parent.prototype.getName = function () {
	return this.name
}
function Child () {
	Parent.apply(this, arguments)
}
Child.prototype = new Parent()
Child.prototype.constructor = Child
// 缺点: 调用两次构造函数生成多余属性 还是多占用内存

寄生组合式继承

function Parent (name) {
	this.name = name
	this.actions = ['sing', 'jump', 'rap']
}
Parent.prototype.getName = function () {
	return this.name
}
function Child () {
	Parent.apply(this, arguments)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child

Object.create内部实现

// 使用中间桥梁连接
let TempFunction = function () {}
TempFunction.prototype = Parent.prototype
Child.prototype = new TempFunction()

为什么不能直接 Child.prototype = Parent.prototype ?
子的原型对象调用父的原型对象,一旦子的原型上增加方法,父的原型也会改变

class继承

class Parent {
	constructor () {}
}
class Child extends Parent {
	constructor () {
		super()
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值