[JS设计模式]Prototype Pattern

Prototype pattern

Prototype pattern可便于同类型的多个对象共享属性。原型(prototype)是JS原生的对象,其他对象可以通过原型链(prototype chain)来访问原型。单独看这句描述可能还是有点儿抽象,下面通过具体的示例来详细阐述。

javascript 复制代码
class Dog {
	constructor(name) {
		this.name = name;
	}

	bark() {
		return `Woof!`;
	}
}

const dog1 = new Dog("Kadi");
console.log(dog1.__proto__);
console.log(Dog.prototype);

这里可以看到,constructor有一个name属性;根据ES6类的语法规则,所有在类中定义的属性(本例的属性bark),都自动加入到类的prototype中,Dog类本身有两个属性:constructor和bark。

有两种方式可以查看类的原型中的属性 ,一种是通过类本身的prototype,另一种是通过实例的__proto__。

从上图的调试信息可以看到,Dog类的prototype也是一个object,其中有两个属性bark和constructor,另外还有一个原型对象([[Prototype]])。

通常类的实例的__proto__直接引用类的prototype,如果类本身不包含某个属性,JS就会向下搜索原型链,查看在原型链中是否能找到被访问的属性。而在dog1实例中,发现有两个[[prototype]],而且还有包含关系,这就是所谓的原型链。

因为所有实例都可以访问类的原型对象,因此原型模式使得实例在访问相同属性时,不用每次都创建该属性的副本。只需要将属性加入到原型中,则所有的实例都可以访问。另外,在创建实例对象后,也支持添加新的属性到原型中,其他实例对象也可以访问这个新加入的属性。

javascript 复制代码
const dog2 = new Dog("Husky")
Dog.prototype.play = ()=> console.log(`playing`);
dog1.play();

我们再创建一个"Husky"的实例,然后对Dog类的原型添加一个新的属性play,接着通过dog1实例来调用play函数,看能否正常运行。


从运行结果来看,dog1能正常访问play属性。

再举个例子,定义一个SuperDog并继承Dog,SuperDog有一个fly属性。通过创建一个SuperDog的实例dog3,且dog3调用bark属性

javascript 复制代码
class SuperDog extends Dog {
	constructor(name) {
		super(name);
	}

	fly() {
		console.log("Flying!");
	}
}

const dog3 = new SuperDog("Super")
dog3.fly();
dog3.bark();
console.log(dog3.__proto__);

此示例中有3级原型链,实例访问属性的搜索路径也非常清晰。dog3.proto -> SuperDog.prototype -> Dog.prototype。

完整示例代码

javascript 复制代码
class Dog {
	constructor(name) {
		this.name = name;
	}

	bark() {
		console.log("Woof!");
	}
}

class SuperDog extends Dog {
	constructor(name) {
		super(name);
	}

	fly() {
		console.log("Flying!");
	}
}

const dog1 = new Dog("Kadi");
console.log(dog1.__proto__);
console.log(Dog.prototype);

const dog2 = new Dog("Husky")
Dog.prototype.play = ()=> console.log(`playing`);

dog1.play();

const dog3 = new SuperDog("Super")
dog3.fly();
dog3.bark();
console.log(dog3.__proto__);

debugger
相关推荐
全栈前端老曹11 分钟前
【前端路由】React Router 权限路由控制 - 登录验证、私有路由封装、高阶组件实现路由守卫
前端·javascript·react.js·前端框架·react-router·前端路由·权限路由
zhuà!32 分钟前
uv-picker在页面初始化时,设置初始值无效
前端·javascript·uv
摸鱼的春哥36 分钟前
实战:在 Docker (Windows) 中构建集成 yt-dlp 的“满血版” n8n 自动化工作流
前端·javascript·后端
Geoking.37 分钟前
【设计模式】装饰者模式详解
设计模式·装饰器模式
_Rookie._38 分钟前
关于迭代协议:可迭代协议和迭代器协议,生成器函数 生成器对象的理解
javascript·python
测试游记43 分钟前
基于 FastGPT 的 LangChain.js + RAG 系统实现
开发语言·前端·javascript·langchain·ecmascript
Van_captain1 小时前
rn_for_openharmony常用组件_Empty空状态
javascript·开源·harmonyos
zhengxianyi5151 小时前
数据大屏-单点登录ruoyi-vue-pro
前端·javascript·vue.js
我想回家种地1 小时前
python期末复习重点
前端·javascript·python
Van_Moonlight1 小时前
RN for OpenHarmony 实战 TodoList 项目:底部 Tab 栏
javascript·开源·harmonyos