JavaScript 是一门基于原型的编程语言,而不是基于类的语言。尽管如此,很多现代 JavaScript 的特性和语法可能会让开发者误以为 JavaScript 支持传统意义上的“类”。让我们来深入了解这个话题。

JavaScript is a prototype-based programming language, not a class-based one. However, many modern JavaScript features and syntax might lead developers to mistakenly believe that JavaScript supports traditional "classes." Let's dive deeper into this topic.

ES6 是什么?What is ES6?

ES6(也称为 ECMAScript 2015)是 JavaScript 的一个重大更新版本,发布于2015年。ES6 引入了许多新功能和语法改进,使得 JavaScript 编程变得更加现代和高效。以下是 ES6 的一些关键特性:

ES6 (also known as ECMAScript 2015) is a major update to JavaScript, released in 2015. ES6 introduced numerous new features and syntax enhancements, making JavaScript programming more modern and efficient. Here are some key features of ES6:

  • 箭头函数(Arrow Functions):简化了函数声明的语法,并且改变了 this 的绑定规则。Arrow Functions: They simplify function declaration syntax and change the this binding rules.

    const greet = () => {
        console.log("Hello, World!");
    };
    
  • 模板字符串(Template Strings):允许多行字符串和内嵌表达式。Template Strings: Allow for multi-line strings and embedded expressions.

    const name = "Alice";
    console.log(`Hello, ${name}!`);
    
  • 解构赋值(Destructuring Assignment):从数组或对象中提取数据,并赋值给变量。Destructuring Assignment: Extracts data from arrays or objects and assigns it to variables.

    let [a, b] = [1, 2];
    let {x, y} = {x: 1, y: 2};
    
  • 块级作用域(Block Scoping):通过 letconst 提供了更好的变量声明机制,解决了 var 声明的变量作用域问题。Block Scoping: With let and const, it provides better variable declaration mechanisms, addressing issues with var scope.

    if (true) {
        let x = 5;
    }
    console.log(x); // Error: x is not defined
    
  • 类语法糖(Class Syntax Sugar):虽然 JavaScript 依然是基于原型的,但 ES6 引入了 class 关键字,提供了一种更直观的语法来创建对象和处理继承,这看起来非常像传统的类系统。Class Syntax Sugar: Although JavaScript remains prototype-based, ES6 introduced the class keyword, offering a more intuitive syntax for creating objects and handling inheritance, which looks very much like traditional class systems.

    class Person {
        constructor(name) {
            this.name = name;
        }
    
        sayHello() {
            console.log(`Hello, my name is ${this.name}`);
        }
    }
    
    const person = new Person("John");
    person.sayHello();
    
  • 模块(Modules):引入原生的模块系统,通过 importexport 来实现代码模块化。Modules: Introduced a native module system, using import and export for code modularization.

    // moduleA.js
    export function hello() {
        console.log('Hello from moduleA!');
    }
    
    // main.js
    import { hello } from './moduleA.js';
    hello();
    
  • Promise:用于处理异步操作,提供了一种更加可靠的方式来处理回调地狱。Promises: Used for handling asynchronous operations, providing a more reliable way to manage callback hell.

    new Promise((resolve, reject) => {
        setTimeout(() => resolve("Success!"), 1000);
    })
    .then(result => console.log(result))
    .catch(error => console.error(error));
    

尽管 ES6 带来了 class 关键字,但这并不是引入了一个新的“类”系统。实际上,class 仅仅是一个语法糖,它是在底层使用了 JavaScript 原有的原型继承机制。这意味着 JavaScript 仍然是原型继承,class 只是为了让代码更加易读和编写更加符合传统面向对象编程的习惯。

Despite ES6 introducing the class keyword, it does not bring a new "class" system. In reality, class is just syntactic sugar; it uses JavaScript's existing prototype inheritance mechanism under the hood. This means JavaScript is still prototype-based, and class is merely for making the code more readable and to write in a style more familiar to traditional object-oriented programming.

因此,即使在 ES6 之后,JavaScript 依然没有真正的类体系结构,而是一种伪类(pseudo-classical)继承,它通过原型链来实现对象的继承和方法共享。理解这一点对于正确地使用 JavaScript 的面向对象特性非常重要。

Therefore, even after ES6, JavaScript does not have a true class architecture but rather a pseudo-classical inheritance, which is achieved through the prototype chain for object inheritance and method sharing. Understanding this is crucial for correctly utilizing JavaScript's object-oriented features.

让我来证明给你看 Let Me Prove It to You

看着这段代码,它使用 class 关键字创建了一个类:Fish.

Look at this code, which uses the class keyword to create a class: Fish.

"use strict";
class Fish {
    name;
    constructor(name) {
        this.name = name;
    }
    swim() {
        console.log(`${this.name} is swimming`);
    }
}
let nemo = new Fish("Nemo");
nemo.swim();

到浏览器里去看一下:

Check it out in the browser:

An image to describe post

看,Fish 是一个函数。

See, Fish is a function.

另外,如果在 Fish 后面输入一个点 . 可以看到 Fish 还有许多属性和方法。看,Fish 竟然还是一个对象。

Moreover, if you type a dot . after Fish, you'll see Fish has many properties and methods. Look, Fish is actually an object.

An image to describe post

Fish 有个 constructor 属性,是一个叫做 Function 的构造函数。

Fish has a constructor property, which is a constructor function called Function.

Function 构造出了 Fish 这个对象,Fish 同时还是一个由 class 关键字定义的函数,在 Fish 前加上个关键字 new 创建出名为 nemo 的对象。

The Function constructor created the Fish object, which is also a function defined by the class keyword. By adding the new keyword before Fish, we create an object named nemo.

那么,Fish 这个伪类有没有可以就是一个构造函数?来验证一下:

So, is Fish just a constructor function? Let's verify:

An image to describe post

Fish 果然是 nemo 的构造函数。

Indeed, Fish is the constructor of nemo.

说明 | Note

ES6 是什么由 Grok AI 生成,我只是按照从 Mosh Hamedani 那里学会的方法,通过代码试着寻找答案,验证猜想。(效果还挺好!)

The explanation of what ES6 is was generated by Grok AI. I just followed the method I learned from Mosh Hamedani, trying to find answers and verify hypotheses through code. (It works pretty well for me!)