JS优雅的使用function实现一个class
本文详解如何使用ES5的Function语法高保真模拟ES6 Class特性。通过判断this指向解决new调用限制,利用Object.defineProperty设置enumerable:false实现方法不可枚举,并添加严格模式与new调用检查,完整还原Class的行为与限制。
正文
利用Function构造器来模拟Class类在JavaScript中并不罕见,但要实现高保真的模拟,必须深入处理各类细节,从而更透彻地理解Class的底层机制。
接下来开始具体实现Class的模拟。
class MyClass{
constructor(name){
this.name = name
}
fun(){
console.log('myName:'+this.name)
}
}
这里展示一个基础的Class定义,随后我们将使用Function对其进行等价实现。
function MyClass1(name){
this.name = name
}
MyClass1.prototype.fun = function(){
console.log('myName:'+this.name)
}
let m1 = new MyClass1('aaa')
m1.fun() //myName:aaa
继续完善Function的实现细节,我们逐步进行。
Tip1:Class只能通过new调用
class MyClass{
constructor(name){
this.name = name
}
fun(){
console.log('myName:'+this.name)
}
}
// MyClass('aaa') //TypeError: Class constructor MyClass cannot be invoked without 'new'
类的实例化必须通过new关键字,直接调用会报错。下面我们在Function中实现这一限制。
如何区分new调用与直接调用?关键在于this的指向,如果不熟悉,可以通过打印日志来观察。
function MyClass1(name){
console.log(this)
this.name = name
}
let m1 = new MyClass1('aaa') //MyClass1 {}
MyClass1('aaa') //window
- 当使用new调用时,函数内部的this指向新创建的实例(即new绑定)。
- 如果是直接调用,this则指向全局对象(默认绑定)。
基于上述特性,我们可以在构造函数内部判断this是否指向实例,若非实例则抛出错误,从而模拟Class的行为。
function MyClass1(name){
console.log(this)
if(!(this instanceof MyClass)){ //如果this不是指向MyClass
throw new TypeError('TypeError: Class constructor MyClass cannot be invoked without 'new'')
}
this.name = name
}
Tip2:Class中的函数不能被枚举
let m = new MyClass('aaa')
for(let i in m){
console.log(i) //name
}
let m1 = new MyClass1('aaa')
for(let i in m1){
console.log(i) //name fn
}
从枚举可以看出,类中的方法无法被for-in枚举。我们可以利用enumerable属性,通过Object.defineProperty修改原型上的方法属性。
'use strict'
function MyClass1(name){
this.name = name
}
Object.defineProperty(MyClass1.prototype,'fn',{
value:function(){
console.log('myName:'+this.name)
},
enumerable:false
})
至此,我们的实现更加完善。
Tip3:Class中的函数不能被new调用
同样涉及new调用的限制,Class中的方法不允许被再次new调用。
let m = new MyClass('aaa')
new m.fun() //TypeError: m.fun is not a constructor
直接new方法会抛出错误,因此在Function实现中也需要避免此问题。由于Function中的普通函数通常允许new调用,我们需要进行修正,利用之前判断new的经验即可解决。
Object.defineProperty(MyClass1.prototype,'fn',{
value:function(){
//不可通过new调用
console.log(this) //正常调用下的this是指向实例 MyClass1 { name: 'aaa' }
if(!(this instanceof MyClass1){//那么相反 不是正常调用的就是错误的调用
//error
}
console.log('myName:'+this.name)
},
enumerable:false
})
同样通过判断this的指向:正常调用时this指向实例MyClass1,若非此指向则为错误调用。
最后是一个细微的细节处理。
Tip4:在ES6中使用类语法,代码默认在严格模式下运行
因此,使用Function实现时,需要在代码开头添加'use strict'。
'use strict'
function MyClass1(name){
this.name = name
}
Object.defineProperty(MyClass1.prototype,'fn',{
value:function(){
console.log(this)
if(!(this instanceof MyClass1)){
//error
throw TypeError('error')
}
console.log('myName:'+this.name)
},
enumerable:false
})
let m1 = new MyClass1('aaa')
m1.fn()
// new m1.fn() //error
for(let i in m1){
console.log(i) //name
}
恭喜你完整阅读,希望对你有所帮助。
到这里我们就完结撒花啦~~
以上就是JS优雅的使用function实现一个class的详细内容,更多关于JS使用function实现class的资料请关注本站其它相关文章!
JS动态构建复杂嵌套JSON对象的方法
2026-11-05 15:41:52
JS负数取余为什么是负数?详解余数与模运算区别
2026-11-05 13:34:41
JS 解压出现乱码或报错怎么解决?
2026-11-05 12:32:38
JS 中 startsWith、indexOf 与正则判断字符串前缀的对比
2026-11-04 22:19:43
JS解析Excel后怎么将数据转换为JSON格式
2026-11-04 20:58:28
