使用不带“class”关键字的 JavaScript 类

举报
Q神 发表于 2023/06/30 21:54:11 2023/06/30
【摘要】 JavaScript 中的类既强大又奇怪。虽然它们允许我们创建具有类似用途的方法和属性的命名对象,但由于语言本身的细微差别,它们经常被误解。但您是否知道在 2015 年之前,JavaScript 甚至没有关键字class作为该语言的一部分?尽管如此,当时的许多程序都使用经典的面向对象编程(OOP)方法,例如使用类、扩展它,甚至添加静态方法。但没有class方法,他们怎么上课呢?好问题!让我们...

JavaScript 中的类既强大又奇怪。虽然它们允许我们创建具有类似用途的方法和属性的命名对象,但由于语言本身的细微差别,它们经常被误解。

但您是否知道在 2015 年之前,JavaScript 甚至没有关键字class作为该语言的一部分?

尽管如此,当时的许多程序都使用经典的面向对象编程(OOP)方法,例如使用类、扩展它,甚至添加静态方法。

但没有class方法,他们怎么上课呢?

好问题!让我们回答这个问题,然后看看:

  • 如何创建一个没有class关键字的“类”
  • 如何“延长”“班级”
  • 如何向我们的“类”添加静态方法

创建公共字段contructor

让我们看一个现代的 JavaScript 类:

class User {
    name = "Corbin",
    username = "crutchcorn",
    sayCatchphrase() {
        console.log("It depends");
    }
}

这是一个相当基本的类,有两个属性(nameusername)以及一个sayCatchphrase方法。

然而,尽管ES6 于 2015 年添加了class关键字,但直到 ECMAScript 2020 才添加这样的公共字段

JavaScript 兼容性表显示对 Node 6 中添加的原始 `class` endraw 的支持,但在 Node 12 中添加了“公共字段”

那么2015年之后2020年之前的班级是如何获得房产的呢?

答案?方法constructor

class User {
    constructor() {
        this.name = "Corbin",
        this.username = "crutchcorn",
    }

    sayCatchphrase() {
        console.log("It depends");
    }
}

事实上,使用这个constructor方法,我们甚至可以添加该方法:

class User {
    constructor() {
        this.name = "Corbin",
        this.username = "crutchcorn",
        this.sayCatchphrase = function() {
            console.log("It depends");
        }
    }
}

当然,这是一个有趣的事实 - 但它并没有回答如何开设课程的问题。

别担心,我们就到了!

创建一个不带class关键字 的类

在我们回答“如何在没有关键字的 JavaScript 中创建一个类class”的问题之前,让我们退一步看看 aclass实际上在做什么......

毕竟,像User上面这样的类可能会创建一个像这样的对象:

const userObject = {
    name: "Corbin",
    username: "crutchcorn",
    sayCatchphrase: function() {
        console.log("It depends");
    }
}

知道了这一点,我们可能会认为创建一个没有关键字的类的最佳方法是从函数返回一个对象:

function User() {
    return {
        name: "Corbin",
        username: "crutchcorn",
        sayCatchphrase: function() {
            console.log("It depends");
        }
    }
}

果然,如果我们使用以下命令运行这段代码:

const user = new User();
user.sayCatchphrase(); // "It depends"

它将按预期运行。然而,它并不能解决所有情况。例如:

new User() instanceof User; // false

相反,如果我们只是将上述类的constructor主体转换为函数会怎么样?:

function User() {
    this.name = "Corbin";
    this.username = "crutchcorn";
    this.sayCatchphrase = function() {
        console.log("It depends");
    }
}

现在,我们不仅使该方法有效,而且instanceof还有效:

const user = new User();
user.sayCatchphrase(); // "It depends"
new User() instanceof User; // true

原型操作

但是从类更改为函数肯定不允许您以相同的方式更改原型吗?

事实上,确实如此!这就是整个事情的运作方式!

考虑以下代码:

function User() {
    this.name = "Corbin";
    this.username = "crutchcorn";
}

User.prototype.sayCatchphrase = function() {
   console.log("It depends");
}

这与之前添加方法的方法相同this.sayCatchphrase,但是是通过更改原型来完成的。

我们可以通过运行来测试这段代码是否仍然有效:

const user = new User();
user.sayCatchphrase(); // "It depends"

super使用该方法 创建扩展类

在讨论基于函数的类扩展之前,我们需要再次讨论一下 ES2020 之前的类创建。

看,当我们将以下代码转换为使用 a 时contructor

class Person {
    personality = "quirky";
}

class Corbin extends Person {
    name = "Corbin";
}

就像这样:

class Person {
    constructor() {
        this.personality = "quirky";
    }
}

class Corbin extends Person {
    constructor() {
        this.name = "Corbin";
    }
}

并尝试初始化它:

const corn = new Corbin()

我们得到以下错误:

Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
    at new Corbin (<anonymous>:9:6)

这是因为我们没有使用该super()方法来告诉我们的扩展类使用父类的方法。

为了解决这个问题,我们将该方法添加到扩展类中constructor

class Person {
    constructor() {
        this.personality = "quirky";
    }
}

class Corbin extends Person {
    constructor() {
        super();
        this.name = "Corbin";
    }
}

现在我们的Corbin构造函数工作按预期进行:

const corn = new Corbin();
console.log(corn.name); // "Corbin";
console.log(corn.personality); // "quirky";

使用扩展功能类Object.create

现在让我们将我们的PersonCorbin类转换为使用函数而不是class关键字。

person 类很简单:

function Person() {
    this.personality = "quirky";
}

我们可以使用call方法将 绑定PersonthisCorbin如下所示:

function Corbin() {
    Person.call(this);
    this.name = "Corbin";
}

一开始它似乎有效:

const corn = new Corbin();
console.log(corn.name); // "Corbin";
console.log(corn.personality); // "quirky";

但现在,再一次,如果我们调用instanceof它,它不支持基类:

new Corbin() instanceof Corbin; // true
new Corbin() instanceof Person; // false

为了解决这个问题,我们需要告诉 JavaScript 使用prototypeofPerson并将其与 的原型结合起来Corbin,如下所示:

function Person() {
}

Person.prototype.personality = "quirky";

function Corbin() {
}

Corbin.prototype = Object.create(Person.prototype);
Corbin.prototype.name = "Corbin";

const corn = new Corbin();
corn.personality // "quirky"
corn.name // "Corbin"

const pers = new Person();
pers.personality // "quirky"
pers.name // undefined

请注意我们如何使用Object.create其他原型创建基础对象

静态方法

让我们通过讨论如何向函数类添加静态方法来结束本文。

回顾一下,ES2020 类上的静态方法如下所示:

class User {
    name = "Corbin",
    username = "crutchcorn",
    static sayCatchphrase() {
        console.log("It depends");
    }
}

User.sayCatchphrase(); // "It depends"
User.name // undefined

const corn = new User();
corn.name; // "Corbin"

这可以通过在函数体之外提供函数名称的键来添加:

function User() {
    this.name = "Corbin",
    this.username = "crutchcorn",
}

User.sayCatchphrase() {
    console.log("It depends");
}


User.sayCatchphrase(); // "It depends"
User.name // undefined

const corn = new User();
corn.name; // "Corbin"

结论

这是对如何在没有class关键字的情况下使用 JavaScript 类的有趣研究。

希望这有助于消除一些关于类在 JavaScript 中如何工作的误解,或者可能只是给出了一些代码为何如此编写的历史背景。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。