当前位置:网站首页>知其然,而知其所以然,JS 对象创建与继承【汇总梳理】
知其然,而知其所以然,JS 对象创建与继承【汇总梳理】
2022-07-03 18:35:00 【51CTO】
小序
在 6 月更文中零零散散讲了 JS 的对象创建和对象继承,有工友对此还是表示疑惑,要注意:这是两个不同但又相关的东西,千万别搞混了!
这些文章是:
- 蓦然回首,“工厂、构造、原型”设计模式,正在灯火阑珊处
- JS精粹,原型链继承和构造函数继承的 “毛病”
- “工厂、构造、原型” 设计模式与 JS 继承
- JS 高级程序设计 4:class 继承的重点
- JS class 并不只是简单的语法糖!
本篇作为汇总篇,来一探究竟!!冲冲冲
对象创建
不难发现,每一篇都离不开工厂、构造、原型这 3 种设计模式中的至少其一!
让人不禁想问:JS 为什么非要用到这种 3 种设计模式了呢??
正本溯源,先从对象创建讲起:
我们本来习惯这样声明对象(不用任何设计模式)
当有两个或多个这样的对象需要声明时,是不可能一直复制写下去的:
这样写:
- 写起来麻烦,重复的代码量大;
- 不利于修改,比如当 car 对象要增删改一个属性,需要多处进行增删改;
工厂函数
肯定是要封装啦,第一个反应,可以 借助函数 来帮助我们批量创建对象~
于是乎:
function makeCar(price,color,performance){
let obj = {}
obj.price = price
obj.color= color
obj.run = ()=>{console.log(performance)}
return obj
}
let car1= makeCar("100","white","run fast")
let car2= makeCar("200","black","run slow")
let car3= makeCar("300","red","broken")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
这就是工厂设计模式在 JS 创建对象时应用的由来~
到这里,对于【对象创建】来说,应该够用了吧?是,在不考虑扩展的情况下,基本够用了。
但这个时候来个新需求,需要创建 car4、car5、car6 对象,它们要在原有基础上再新增一个 brand
属性,会怎么写?
第一反应,直接修改 makeCar
function makeCar(price,color,performance,brand){
let obj = {}
obj.price = price
obj.color= color
obj.run = ()=>{console.log(performance)}
obj.brand = brand
return obj
}
let car4= makeCar("400","white","run fast","benz")
let car5= makeCar("500","black","run slow","audi")
let car6= makeCar("600","red","broken","tsl")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
这样写,不行,会影响原有的 car1、car2、car3 对象;
那再重新写一个 makeCarChild
工厂函数行不行?
function makeCarChild (price,color,performance,brand){
let obj = {}
obj.price = price
obj.color= color
obj.run = ()=>{console.log(performance)}
obj.brand = brand
return obj
}
let car4= makeCarChild("400","white","run fast","benz")
let car5= makeCarChild("500","black","run slow","audi")
let car6= makeCarChild("600","red","broken","tsl")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
行是行,就是太麻烦,全量复制之前的属性,建立 N 个相像的工厂,显得太蠢了。。。
构造函数
于是乎,在工厂设计模式上,发展出了:构造函数设计模式,来解决以上复用(也就是继承)的问题。
function MakeCar(price,color,performance){
this.price = price
this.color= color
this.run = ()=>{console.log(performance)}
}
function MakeCarChild(brand,...args){
MakeCar.call(this,...args)
this.brand = brand
}
let car4= new MakeCarChild("benz","400","white","run fast")
let car5= new MakeCarChild("audi","500","black","run slow")
let car6= new MakeCarChild("tsl","600","red","broken")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
构造函数区别于工厂函数:
- 函数名首字母通常大写;
- 创建对象的时候要用到 new 关键字(new 的过程这里不再赘述了,之前文章有);
- 函数没有 return,而是通过 this 绑定来实现寻找属性的;
到此为止,工厂函数的复用也解决了。
构造+原型
新的问题在于,我们不能通过查找原型链从 MakeCarChild 找到 MakeCar
无论在原型链上怎么找,都无法从 MakeCarChild
找到 MakeCar
这就意味着:子类不能继承父类原型上的属性
这里提个思考问题:为什么“要从原型链查找到”很重要?为什么“子类要继承父类原型上的属性”?就靠 this 绑定来找不行吗?
于是乎,构造函数设计模式 + 原型设计模式 的 【组合继承】应运而生
function MakeCar(price,color,performance){
this.price = price
this.color= color
this.run = ()=>{console.log(performance)}
}
function MakeCarChild(brand,...args){
MakeCar.call(this,...args)
this.brand = brand
}
MakeCarChild.prototype = new MakeCar() // 原型继承父类的构造器
MakeCarChild.prototype.constructor = MakeCarChild // 重置 constructor
let car4= new MakeCarChild("benz","400","white","run fast")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
现在再找原型,就找的到啦:
其实,能到这里,就已经很很优秀了,该有的都有了,写法也不算是很复杂。
工厂+构造+原型
但,总有人在追求极致。
上述的组合继承,父类构造函数被调用了两次,一次是 call 的过程,一次是原型继承 new 的过程,如果每次实例化,都重复调用,肯定是不可取的,怎样避免?
工厂 + 构造 + 原型 = 寄生组合继承 应运而生
核心是,通过工厂函数新建一个中间商 F( ),复制了一份父类的原型对象,再赋给子类的原型;
function object(o) { // 工厂函数
function F() {}
F.prototype = o;
return new F(); // new 一个空的函数,所占内存很小
}
function inherit(child, parent) { // 原型继承
var prototype = object(parent.prototype)
prototype.constructor = child
child.prototype = prototype
}
function MakeCar(price,color,performance){
this.price = price
this.color= color
this.run = ()=>{console.log(performance)}
}
function MakeCarChild(brand,...args){ // 构造函数
MakeCar.call(this,...args)
this.brand = brand
}
inherit(MakeCarChild,MakeCar)
let car4= new MakeCarChild("benz","400","white","run fast")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
ES6 class
再到后来,ES6 的 class 作为寄生组合继承的语法糖:
class MakeCar {
constructor(price,color,performance){
this.price = price
this.color= color
this.performance=performance
}
run(){
console.log(console.log(this.performance))
}
}
class MakeCarChild extends MakeCar{
constructor(brand,...args){
super(brand,...args);
this.brand= brand;
}
}
let car4= new MakeCarChild("benz","400","white","run fast")
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
有兴趣的工友,可以看下 ES6 解析成 ES5 的代码:原型与原型链 - ES6 Class的底层实现原理 #22
对象与函数
最后本瓜想再谈谈关于 JS 对象和函数的关系:
即使是这样声明一个对象,let obj = {}
,它一样是由构造函数 Object
构造而来的:
在 JS 中,万物皆对象,对象都是有函数构造而来,函数本身也是对象。
对应代码中的意思:
- 所有的构造函数的隐式原型都等于 Function 的显示原型,函数都是由 Function 构造而来,Object 构造函数也不例外;
- 所有构造函数的显示原型的隐式原型,都等于 Object 的显示原型,Function 也不例外;
这个设计真的就一个大无语,大纠结,大麻烦。。。
只能先按之前提过的歪理解记着先:Function 就是上帝,上帝创造了万物;Object 就是万物。万物由上帝创造(对象由函数构造而来),上帝本身也属于一种物质(函数本身却也是对象);
对于本篇来说,继承,其实都是父子构造函数在继承,然后再由构造函数实例化对象,以此来实现对象的继承。
到底是谁在继承?函数?对象?都是吧~~
小结
本篇由创建对象说起,讲了工厂函数,它可以做一层最基本的封装;
再到,对工厂的拓展,演进为构造函数;
再基于原型特点,构造+原型,得出组合继承;
再追求极致,讲到寄生组合;
再讲到简化书写的 Es6 class ;
以及最后对对象与函数的思考。
就先到这吧~~
OK,以上便是本篇分享。点赞关注评论,为好文助力
我是掘金安东尼 100 万人气前端技术博主 INFP 写作人格坚持 1000 日更文 关注我,安东尼陪你一起度过漫长编程岁月
边栏推荐
- An academic paper sharing and approval system based on PHP for computer graduation design
- [combinatorics] generating function (example of generating function | calculating generating function with given general term formula | calculating general term formula with given generating function)
- What is SQL get connection
- Use of unsafe class
- 204. Count prime
- Theoretical description of linear equations and summary of methods for solving linear equations by eigen
- Prototype inheritance..
- Golang string (string) and byte array ([]byte) are converted to each other
- Reading a line from ifstream into a string variable
- 2022-2028 global aircraft head up display (HUD) industry research and trend analysis report
猜你喜欢
Caddy server agent
4. Load balancing and dynamic static separation
Lesson 13 of the Blue Bridge Cup -- tree array and line segment tree [exercise]
12、 Service management
Redis cache avalanche, penetration, breakdown
2022-2028 global marking ink industry research and trend analysis report
Valentine's day, send you a little red flower~
Win32: analyse du fichier dump pour la défaillance du tas
How many convolution methods does deep learning have? (including drawings)
Unity webgl optimization
随机推荐
Prototype inheritance..
204. Count prime
Sepconv (separable revolution) code recurrence
AcWing 271. Teacher Yang's photographic arrangement [multidimensional DP]
[combinatorics] generating function (positive integer splitting | unordered | ordered | allowed repetition | not allowed repetition | unordered not repeated splitting | unordered repeated splitting)
Torch learning notes (4) -- torch's dynamic calculation diagram
Sensor 调试流程
[combinatorics] generating function (use generating function to solve the number of solutions of indefinite equation)
Coordinate layer conversion tool (video)
Multifunctional web file manager filestash
Torch learning notes (1) -- 19 common ways to create tensor
[combinatorics] generating function (positive integer splitting | unordered non repeated splitting example)
Implementation of cqrs architecture mode under Kratos microservice framework
[combinatorics] generating function (positive integer splitting | basic model of positive integer splitting | disordered splitting with restrictions)
Torch learning notes (6) -- logistic regression model (self training)
[combinatorics] generating function (use generating function to solve the combination number of multiple sets R)
[combinatorics] generating function (use generating function to solve the number of solutions of indefinite equation example 2 | extended to integer solution)
4. Load balancing and dynamic static separation
[linux]centos 7 reports an error when installing MySQL "no package MySQL server available" no package ZABBIX server MySQL available
Computer graduation design PHP makeup sales Beauty shopping mall