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

相关推荐
masa0103 分钟前
JavaScript--JavaScript基础
开发语言·javascript
一只特立独行的猪6111 小时前
Java面试——集合篇
java·开发语言·面试
让开,我要吃人了2 小时前
HarmonyOS开发实战(5.0)实现二楼上划进入首页效果详解
前端·华为·程序员·移动开发·harmonyos·鸿蒙·鸿蒙系统
everyStudy3 小时前
前端五种排序
前端·算法·排序算法
甜兒.4 小时前
鸿蒙小技巧
前端·华为·typescript·harmonyos
她似晚风般温柔7897 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
王中阳Go7 小时前
字节跳动的微服务独家面经
微服务·面试·golang
Jiaberrr8 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy8 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白8 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http