JS优雅的使用function实现一个class

作者:纸飞机时间:2026-10-26 07:47:40浏览:471

本文详解如何使用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的资料请关注本站其它相关文章!

作者最新文章