对象
一个对象是 Javascript 中的引用数据类型。它由键值对构成,每对键值间使用冒号分隔,键值对之间使用逗号分隔。一个对象可以为空或拥有无数个属性。
对象有比较多的应用。它可以用于将相关的数据封装到一起,形成一系列有关联的数据和功能,这些相关数据和功能被封装在一个对象中,这种设计思想就称为面向对象编程。
对于前端开发者来说,对象是非常常见的,它可以用于存储当前页面的状态、响应用户事件等。此外,许多前端框架(如 Vue.js、React 等)都使用对象进行组件化开发和状态管理。
原型链
- 在Javascript中,每个对象都有一个内置的属性
[[Prototype]]
,它指向对象的原型(prototype)。 - 对象的原型也可以有自己的原型,这样一直延续下去就形成了原型链。
- 在JS中,如果你想要访问一个对象上的某个方法或属性,但该对象本身并没有该方法或属性,那么Javascript会自动查找该对象的原型,
- 如果原型上也没有该方法或属性,那么Javascript将继续沿着原型链继续查找,直到找到该方法或属性为止。
- 原型链是Javascript中继承的基础,也是Javascript中许多特性的基础之一。
构造函数
- 构造函数原型是JS中所有函数对象都具有的一个属性,是一个对象,包含了所有由该构造函数创建的对象所共享的属性和方法。
- 通过向构造函数原型对象上添加属性和方法,可以实现多个实例共享同一属性或方法的效果。
- 在构造函数中,可以通过this关键字给实例添加一些独特的属性和方法。
//下面的代码演示了使用构造函数和构造函数原型创建一个Person对象,并输出对象的属性。
// 使用构造函数创建一个Person对象
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greeting = function() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
const person1 = new Person('John', 30);
person1.greeting(); // 输出:Hello, my name is John and I am 30 years old.
// 在上述示例中,我们首先定义了一个名为Person的构造函数,这个构造函数接收name和age两个参数。
// 然后,我们使用this关键字将这两个参数赋值给新建对象的属性。
// 最后,我们在Person函数的原型对象上添加了一个greeting方法,在方法中输出一条问候语。
// 通过这种方式,我们可以在实例中访问原型中定义的方法和属性。
Class对象
缺点
Class对象的缺点有以下几点:
- JavaScript中的类是基于原型继承机制实现的语法糖,本质上依然是通过原型链来实现继承,因此如果使用不当,仍然可能造成原型链深度过深、原型污染等问题。
- Class对象中的getter和setter只能定义在属性的descriptor中,因此不能像普通方法一样被定义在原型上,这使得在Class对象中实现比较复杂的计算属性变得比较困难。
- 在使用Class对象的继承机制时,必须通过super关键字来引用父类的方法和属性,这在某些情况下并不方便。
- Class对象中的静态属性和静态方法只能通过Class对象本身来访问,不能被实例所继承。这在一些情况下可能不是很方便。
必要性
- 使用Class对象可以实现更完整、更严格的面向对象编程特性,例如封装、继承、多态等概念。
- 在Class对象中,可以使用关键字static定义静态属性和方法,这些静态属性和方法可以通过Class对象本身直接访问,而不需要实例化对象。
- 此外,Class对象中还支持更加灵活、强大的继承机制,可以实现更加高级的继承特性。
- 与此相比,构造函数相对简单,没有这些高级特性。同时,使用Class对象可以让代码更加简洁、易读。
执行原理
- ES6中的Class对象是JavaScript中的一种新的语法糖,它是在现有基于原型的继承机制之上引入的一个概念。
- 它是JavaScript中一种特殊的函数类型,通过class关键字声明。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
console.log(typeof Person) //输出:function
- class关键字允许我们去声明一个类,并在这个类的内部去定义一些属性和方法。
- 通过类创建实例的过程和构造函数很相似。
- 在类的内部,可以定义属性、方法、getter、setter等。
- Class对象是一种面向对象编程思想的具体体现,通过它可以封装一些特定的数据和方法到一个对象中,并且可以方便地进行组件化开发和状态管理。
- 类声明的执行原理如下:
- 定义类:使用class关键字来定义类,类名一般首字母大写。
- 定义构造函数:通过constructor关键字定义构造函数,用来初始化对象实例。
- 定义方法:在类中定义方法,并将其添加到类原型之中。
- 创建类实例:使用new关键字创建类实例,并传递实例化时需要的参数。
- 访问属性:使用点号(.)访问实例属性,使用this关键字引用类中定义的属性和方法。
// 下面是一个示例,展示如何调用上面示例中定义的Person类,并访问类中定义的属性和方法。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greeting() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
// 使用class创建一个对象实例,并调用其中定义的方法
const person = new Person('John', 30);
person.greeting(); // 输出:Hello, my name is John and I am 30 years old.
constructor
- 在Class对象中,constructor是一个特殊的方法,它用来构造和初始化对象实例。
- 在一个类中,constructor方法会在实例创建时立即执行,并且可以通过this关键字引用当前对象实例。
- 在constructor方法中,可以使用this关键字向对象实例中添加属性和方法。
- 如果在一个类中没有明确定义constructor方法,那么默认会创建一个空的constructor方法。
- 如果需要在实例化对象时传递参数,可以在constructor方法中定义这些参数。
// 下面的代码演示了在Class对象中定义constructor方法和传递参数。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greeting() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
// 使用class创建一个对象实例,并调用其中定义的方法
const person = new Person('John', 30);
person.greeting(); // 输出:Hello, my name is John and I am 30 years old.
- constructor中的变量
- 在Class对象的constructor方法中,可以定义需要使用的参数和属性,并使用this关键字将它们赋值给对象的实例属性。
- 这些实例属性可以在类的方法中使用,并且可以在Class对象创建的实例中访问。
// 下面是一个示例,展示如何在Class对象的constructor方法中定义属性和方法。
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
this.gender = "unknown"; // 在constructor方法中定义了一个名为gender的实例属性。
}
greeting() {
console.log(`Hello, my name is ${this.name}, I am ${this.age} years old, and my gender is ${this.gender}.`);
}
}
const person = new Person("John", 30);
person.gender = "male"; // 将对象实例的gender属性重新赋值为"male"。
person.greeting(); // 输出:Hello, my name is John, I am 30 years old, and my gender is male.
以下是根据您的要求调整后的Markdown格式文章:
- 在使用Class对象时,需要注意以下几点:
- 在一个类中只能定义一个
constructor
方法,不能重复定义。 - 如果需要继承父类的构造函数,需要在子类的
constructor
方法中调用super()
方法。 - 如果一个类不需要定义构造函数,可以省略
constructor
方法。 - 在
constructor
方法中定义的属性和方法都是实例属性和方法,只能通过实例对象进行访问。 - 如果需要定义静态属性和方法,可以使用静态关键字
static
来定义。静态属性和方法是指与类相关联的属性和方法,可以直接通过类来访问,而不需要创建实例对象。
// 下面的代码演示了在Class对象中定义constructor方法和静态属性和方法。
class Person {
static species = "human"; // 使用静态关键字定义一个名为species的静态属性。
static sayHello() { // 使用静态关键字定义一个名为sayHello的静态方法。
console.log("Hello from Person!");
}
constructor(name, age) {
this.name = name;
this.age = age;
}
greeting() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
const person = new Person("John", 30);
person.greeting(); // 输出:Hello, my name is John and I am 30 years old.
console.log(Person.species); // 输出:human
Person.sayHello(); // 输出:Hello from Person!
getter|setter
Class对象的 Descriptor
- 用于给对象中的属性或方法加上介绍性质描述的工具方法叫做descriptor。
- 每个属性都拥有自己的描述符,它们分别是:value、writable、enumerable、configurable。
描述符 | 定义 |
---|---|
value | 属性的实际值。 |
writable | 布尔值,指示属性的值是否可以被更改。 |
enumerable | 布尔值,指示属性是否可以在for...in循环中遍历。 |
configurable | 布尔值,指示属性是否可以被删除或其描述符是否可以被更改。 |
// 在对象定义时,使用Object.defineProperty()方法为属性添加介绍性质描述。
// 下面是一个示例,展示如何使用descriptor定义属性描述符。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
const animal = new Animal("Dog");
Object.defineProperty(animal, "name", { // 使用descriptor定义name属性的描述符。
value: "Cat",
writable: false,
enumerable: false,
configurable: false
});
animal.speak(); // 输出:Cat makes a noise.
console.log(animal.name); // 输出:Cat
// 在使用descriptor时,需要注意以下几点:
// 1. 使用descriptor定义的属性,如果是不可写的,那么它的值将无法被修改。
// 2. 使用descriptor定义的属性,如果不可枚举,那么它将无法通过for-in循环进行遍历。
// 3. 使用descriptor定义的属性,如果不可配置,那么它将无法被删除或者再次修改描述符。
// 4. 使用descriptor定义的属性,如果没有设置任何描述符,默认情况下它的所有描述符值都为false。