JavaScript中的Function与class语法糖

当 JavaScript在2015年发布了ES6标准时,引入了一项重要的功能------类(class)。然而,我们必须明确一点:JavaScript本质上仍然是基于原型的面向对象语言,而类只是一种语法糖,用于更方便地创建和组织对象。本文将来讨论ES6中的类和函数。

首先,让我们明确一点:JavaScript没有传统意义上的类。在JS中,一切都是对象,而函数则是一等公民。函数既可以作为普通函数执行,又可以作为构造函数使用。这就是为什么我们常常听到"JavaScript是一门基于原型的面向对象语言"的说法。而类(class)的引入是为了使JavaScript更适合企业级开发,并以更类似于其他大型语言的方式来实现面向对象编程。

ES6中引入的类是一种语法糖,它实际上并没有改变JavaScript的原型继承机制 (如果对js的原型还不了解,可以先去看一下这篇文章 JavaScript原型与原型链:理解核心概念,构建强大的前端技能)。类只是一种更简洁、更易读的语法形式,用于定义对象的结构和行为。类的声明方式如下:

javascript 复制代码
class Person {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

const person = new Person("John"); 
person.sayHello(); // 输出:Hello, my name is John.

上面的代码定义了一个名为Person的类,具有一个构造函数constructor和一个sayHello的方法。构造函数负责实例化对象并初始化其属性,而方法则定义了对象的行为。我们使用 "new" 关键字创建了一个名为 "person" 的类实例,并调用了它的 "sayHello" 方法。我们需要注意的是,这些方法都是定义在类的原型对象上的,而不是实例本身。这意味着所有类的实例共享相同的方法,这样可以节省内存,因为每个实例可以不用单独保存方法。

函数

在ES6之前,我们使用传统的构造函数、原型对象和实例的方式来创建对象。通过构造函数创建实例时,构造函数内部的this指向新创建的实例。原型对象则通过实例的__proto__属性来保持原型关系,而constructor属性告诉实例它是由哪个构造函数创建的。

javascript 复制代码
    function Person(name){
        this.name = name;
    }
    Person.prototype.sayHello = function(){
        return console.log('hello,I am ' + this.name);
    }
    
    const person = new Person("John"); 
    console.log(Person.prototype===person.__proto__); // 输出true
    person.sayHello(); // 输出:Hello, my name is John.
    

这段代码和上面类的那段代码作用是一样的。

当我们遍历一个对象上的属性时,可以发现原型对象上的属性是可遍历的,但constructor属性除外。我们可以使用Object.keys()方法来获取对象上可遍历的属性。我们到浏览器的控制台上使用Object.keys(Person.prototype)可以看到:

而直接打印Person.prototype,则可以看到它上面还有的constructor属性:

为什么说Class是语法糖

实际上,class的底层原理和Function是一样的,我们换到之前类的那段代码,再去控制台打印Person.prototype,可以看到:

它也有原型,也是通过原型继承来实现对象之间的关系。

另一个需要注意的是,类所声明的方法不可被遍历(枚举),我们使用Object.keys(Person.prototype)得到的是空数组。

类声明的方法默认是不可枚举的。这是因为类的方法通常用于定义对象的行为,而不是作为对象的数据属性。为了避免将类方法错误地当作普通属性进行遍历和操作,类方法被设计为不可枚举。

原型继承可以比喻为对象之间的委托关系,一个对象可以通过指向另一个对象作为其原型,从而继承原型对象的属性和方法。

虽然原型继承灵活且功能强大,但使用起来相对复杂,需要手动设置原型链、构造函数等。这导致了代码可读性不高,编写和阅读对象之间关系的代码变得困难。

ES6 引入了 class 关键字,提供了一种更直观、更易理解的方式来定义对象和对象之间的关系。class 通过将对象和继承的概念封装在一个简洁的语法中,使代码结构更清晰、易于维护。

当我们使用 class 声明一个类时,实际上是在底层使用原型继承来实现类的行为。class 的方法会被添加到构造函数的原型对象上,并通过原型链的方式进行继承。

因此,将 class 称为语法糖是指它只是一种更便捷的语法,封装了底层的原型继承机制,使代码更易于理解和编写。虽然它提供了更类似传统面向对象编程语言的语法,但实质上仍然使用原型继承来实现对象之间的关系。

相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
uhakadotcom8 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
范文杰8 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy9 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
快速开始使用 n8n
后端·面试·github
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github