[原创]Javascript模拟“类”的综合实现方式以及部分细节【截至ES6】

简介: 前言 最近几个旧项目里使用的图片编辑插件出现Bug, 经Review 后确定需要在其内外均做些改动,但是头疼的发现部分页面里的JavaScript 代码被冗余了NN次。部分新同事堆叠了大量的过程式的脚本块(几乎没有利用面向对象封装的概念-虽然面向对象也按需择时),改起来挺累(而且几个项目里各自不同)。
[原创]Javascript模拟“类”的综合实现方式以及部分细节【截至ES6】

前言
 
  最近几个旧项目里使用的图片编辑插件出现Bug, 经Review 后确定需要在其内外均做些改动,但是头疼的发现部分页面里的JavaScript 代码被冗余了NN次。部分新同事堆叠了大量的过程式的脚本块(几乎没有利用面向对象封装的概念-虽然面向对象也按需择时),改起来挺累(而且几个项目里各自不同)。本身插件问题已经解决,但是就代码这块儿,针对面向对象的抽离封装,反而想写些东西。虽然没有太多分享价值,自己也忘记不少,翻了下以前的各种代码草稿,还是想尽量做些相对完整的记录和分享。当然,文中若有不妥,欢迎指正。
 
正文
 
  JavaScript 编程本身是不包含传统“类”的概念的,这是不同于我们偏后端的一些强类型对象语言的(例如Java、C#等),而我们往往会利用funciton、 prototype 等关键字来实现一个类似“类”的原型模型(当然也包括各种继承特性)。从而使得项目中的js更优美,更高效。(截至最新的ECMAScript6里也推出了更简单的标准实现,后面会有相关演示)
 
注:所有Demo 均可直接在我的github上下载(地址:https://github.com/tempbing/Javascript-ClassDemos
 
 
一、首先模拟一个基础版的“类”,常规方式,利用function 和 this 关键字。(这里this关键字 代表调用的当前实例“对象”,不赘述,但初学者一定要深入理解,以前专业书里讲了几十页)。
Tips:这里稍微留意下代码里的相关注释
 
 
相关使用EG:
 
 
二、然后在这个基础"类"上,额外附加更多特征,直接操作prototype演变成一个丰富的“类”(另:这里有些小细节问题,注意下我在注释里说到的部分细节):
 
 
相关使用EG - 读取,这里是一致:
 
 
相关使用EG - 更新,这里则有些需要注意(代码里也包含了详细注释提醒,这里不做主要扩展):
 
 
还是用文字方式啰嗦提醒下:
 
当进行对象原型上的操作时(这里特指使用prototype 附加操作),需要注意一个容易遗漏的关于内存堆栈的小细节。由于数组(这里是Product原型附加的“tags”)属于引用类型(或者说对象类型),如果用类似于C语言里的指针概念解释则更形象,开辟的内存堆栈空间上,若为引用型,修改了该引用的具体值,那么影响的是所有指向当前堆空间的变量。所以上面修改了product02的 tags值后,再查看product01的 tags值也是同样发生了改变。当然,如果直接改了栈值(或者说指针标记),则等同于将当前指针指向了其他堆空间,属于自身改变了,当然就不会影响到指向原来堆的其他标记(比如操作:product02.tags=['AutumnBing'])。 另:其实很多地方均有这样的概念,容易入坑,这里暂且不深入,注意这个小细节就好)
 
三、关于继承,先利用prototype 原型链做个不是太推荐的简单继承(毕竟原型链的操作需要用到恰当地方,见demo):
 
 
相关使用EG:
 
 
 
四、更妥当的继承方式,结合“call” 内部回调,操作上下文来实现,也更安全:
 
 
相关使用EG:
 
 
 
五、目前最新的ES6 中直接推出了专属class概念,作为对象的模板,通过class关键字,可以直接定义封装类 (个人认为更像是一个基于prototype的语法糖,但最起码比ES5的Object.create() 半成品更佳)。
 
 
相关使用EG:
 
 
 
六、同样,针对class,也拥有了新的继承方式。增加extends和super,更加精简直观,这非常类似于JAVA/C#等强类型语言中的继承方式:
 
 
相关使用EG:
 
 
 
结语
 
某些时候,我们对于是否面向对象的编程,会有一些实际考虑。但在代码的模块化、插件化开发里,需是毫无疑问的怀抱面向对象的理念。有些东西并不复杂,但延伸的概念和细节依然需要注意。以上本人结合现有知识,进行归纳和总结了关于“类”的一些相关实现方式,包括一些细节问题。如有不妥之处,欢迎各种方式的指正。所有demo,完整演示代码,刚才已全部提交到我的github上去了(地址:https://github.com/tempbing/Javascript-ClassDemos)。夜深了,准备睡了。
 
End.
 
 

目录
相关文章
|
1月前
|
缓存 JavaScript 数据安全/隐私保护
js开发:请解释什么是ES6的Proxy,以及它的用途。
`ES6`的`Proxy`对象用于创建一个代理,能拦截并自定义目标对象的访问和操作,应用于数据绑定、访问控制、函数调用的拦截与修改以及异步操作处理。
18 3
|
1月前
|
JavaScript
js开发:请解释什么是ES6的类(class),并说明它与传统构造函数的区别。
ES6的类提供了一种更简洁的面向对象编程方式,对比传统的构造函数,具有更好的可读性和可维护性。类使用`class`定义,`constructor`定义构造方法,`extends`实现继承,并可直接定义静态方法。示例展示了如何创建`Person`类、`Student`子类以及它们的方法调用。
22 2
|
1月前
|
自然语言处理 JavaScript 网络架构
js开发:请解释什么是ES6的箭头函数,以及它与传统函数的区别。
ES6的箭头函数以`=>`定义,简化了函数写法,具有简洁语法和词法作用域的`this`。它无`arguments`对象,不能用作构造函数,不支持`Generator`,且不改变`this`、`super`、`new.target`绑定。适用于简短表达式,常用于异步编程和高阶函数。
18 5
|
1月前
|
JavaScript 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承利用原型链查找属性,节省内存但不支持私有成员。类继承通过ES6的class和extends实现,支持私有成员但占用更多内存。两者各有优势,适用于不同场景。
19 0
|
1月前
|
前端开发 JavaScript 开发者
探索JavaScript ES6的八种常见使用技巧:开启现代编程之旅
探索JavaScript ES6的八种常见使用技巧:开启现代编程之旅
|
1月前
uni-app 65egg.js聊天类chat.js封装(二)
uni-app 65egg.js聊天类chat.js封装(二)
25 1
|
2天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可以是任意类型且有序,与对象的字符串或符号键不同;Set存储唯一值,无重复。两者皆可迭代,支持for...of循环。Map有get、set、has、delete等方法,Set有add、delete、has方法。示例展示了Map和Set的基本操作。
16 3
|
2天前
|
JavaScript 前端开发
js开发:请解释什么是ES6的Generator函数,以及它的用途。
ES6的Generator函数是暂停/恢复功能的特殊函数,利用yield返回多个值,适用于异步编程和流处理,解决了回调地狱问题。例如,一个简单的Generator函数可以这样表示: ```javascript function* generator() { yield 'Hello'; yield 'World'; } ``` 创建实例后,通过`.next()`逐次输出"Hello"和"World",展示其暂停和恢复的特性。
10 0
|
1月前
|
JavaScript 前端开发
js开发:请解释什么是ES6的async/await,以及它如何解决回调地狱问题。
ES6的`async/await`是基于Promise的异步编程工具,能以同步风格编写异步代码,提高代码可读性。它缓解了回调地狱问题,通过将异步操作封装为Promise,避免回调嵌套。错误处理更直观,类似同步的try...catch。
|
1月前
|
JavaScript
js开发:请解释什么是ES6的Symbol,以及它的用途。
ES6的Symbol数据类型创建唯一值,常用于对象属性键(防冲突)和私有属性。示例展示了如何创建及使用Symbol:即使描述相同,两个Symbol也不等;作为对象属性如`obj[symbol1] = 'value1'`;也可作枚举值,如`Color.RED = Symbol('red')`。