学习目标
完成本单元后,您将能够:
- 使用对象文字符号和构造函数创建对象。
- 将属性和功能分配给对象。
- 确定原型在JavaScript对象继承中的作用。
- 描述JavaScript类语法。
- 描述闪电网络组件中继承的作用和对象文字表示法。
有很多方法可以将JavaScript描述为一种语言。无论您选择哪种定义,每个人都可以同意对象的JavaScript概念的重要性。您越了解JavaScript对象以及它们如何工作,就越能编写有效的JavaScript。
在开始之前,请先对对象进行一些说明。
- 对象没有Apex,Java或C#开发人员可能会想到的类。
- 每个对象都继承自另一个对象。
- 对象是可变的。
- 对象在创建时会获得自己的变量上下文。
创建对象
从语法上讲,有几种方法可以用JavaScript创建对象。但是,无论您如何创建对象,它实际上都是在抽象一个称为的底层API Object.create()
。
在某些情况下,有充分的理由Object.create()
直接使用,但我们不在此介绍。相反,让我们看一下创建对象的更常见方法。
对象文字表示法
第一个对象创建语法称为对象文字表示法。这是一次同时声明和分配对象的简单声明方式。然后立即将对象分配为同一语句的一部分。
const bike = {
gears: 10,
currentGear: 3,
changeGear: function(direction, changeBy) {
if (direction === 'up') {
this.currentGear += changeBy;
} else {
this.currentGear -= changeBy;
}
}
}
console.log(bike.gears); // 10
console.log(bike.currentGear); //3
bike.changeGear('up', 1);
console.log(bike.currentGear); //4
对象文字符号本质上是声明性的。bike
此 示例中的对象具有三个成员:gears
和currentGear
属性以及changeGear
函数。若要在创建对象后引用这些成员,请使用点表示法。
注意
您可能会注意到JSON和对象文字表示法彼此相似,但是它们并不相同。JSON是一种数据交换格式。对象文字符号是一种编程语法。但是,JSON规范基于对象文字表示法,因此很容易将两者混为一谈。
文字对象非常适合一次性对象。但是,如果要创建两个或更多个相同类型的对象,则它们是不实际的。为此,您需要可重复的逻辑来创建新对象。
构造函数的新对象
创建对象的另一种方法是使用构造函数。构造函数是一种函数,其中包含用于在创建和分配对象时建立对象属性的指令。与对象文字相比,这具有优势,因为您可以创建具有相同属性的对象的许多实例。
function Bike(gears, startGear) {
this.gears = gears;
this.currentGear = startGear;
}
Bike.prototype.changeGear = function(direction,changeBy){
if(direction === 'up') {
this.currentGear += changeBy;
} else {
this.currentGear -= changeBy;
}
}
const bike = new Bike(10, 3);
console.log(bike.gears); // 10
console.log(bike.currentGear); //3
bike.changeGear('up', 1);
console.log(bike.currentGear); //4
在此 示例中, Bike
是定义对象的普通JavaScript函数。我们遵循JavaScript约定并大写第一个单词来表示此函数是构造函数。该new
关键字是至关重要的。如果不使用new
,则this
指针将不会指向您期望的对象,并且会导致意外的行为。this
当我们在以后的单元中介绍上下文时,我们会重新进行讨论。
请注意,该changeGear
函数的分配是通过使用来完成的prototype
。这样可以确保函数定义一次,并由该构造函数创建的所有实例共享。我们将在本单元后面介绍原型的使用和继承。
在语法方面,对象文字表示法和构造函数完全不同。但是在每种情况下,您仍然最终会在内存中创建一个新对象,并使用变量bike
作为指向该对象的指针。使用构造函数,您可以使许多Bike
具有相同属性和功能的对象。
为对象分配属性和功能
如果从bike
上面的示例推断出对象中有两种可能的成员类型-属性和函数-您将是正确的。
属性具有三种基本形状。
- 原语
- 对象
- 数组
有六种基本类型在JavaScript:字符串,数字,布尔null
,undefined
和符号。如果变量是原始类型,则在分配时按值传递。也就是说,每次分配基元时,都会复制值并将其分配给新变量。
几乎所有不是JavaScript中原始语言的东西都是对象。在对象文字表示法中,对象属性用大括号表示。
数组本身也被实现为JavaScript中的对象。可以使用Array()
构造函数或以方括号表示的文字符号来创建数组。
函数在此模块中有其自己的单元,因此我们在这里不再讨论它们,但是基于以上内容,让我们通过bike
使用对象文字符号定义更复杂的对象的方法。
const bike = {
frontGearIndex: 0,
rearGearIndex: 0,
transmission: {
frontGearTeeth: [30,45],
rearGearTeeth: [11,13,15,17,19,21,24,28,32,36]
},
calculateGearRatio: function() {
let front = this.transmission.frontGearTeeth[this.frontGearIndex],
rear = this.transmission.rearGearTeeth[this.rearGearIndex];
return (front / rear);
},
changeGear: function(frontOrRear, newValue) {
if (frontOrRear === 'front') {
this.frontGearIndex = newValue;
} else {
this.rearGearIndex = newValue;
}
}
};
通过括号语法引用属性
引用对象成员通常是使用点符号来完成的。例如,在前面的示例中,我们按如下方式引用对象的属性和功能。
bike.frontGearIndex
bike.transmission.frontGearTeeth
bike.calculateGearRatio()
用点表示法,对属性名称有严格的规定。但是,JavaScript还允许使用另一种称为括号符号的语法。上面的成员将在括号中引用如下。
bike["frontGearIndex"]
bike["transmission"]["frontGearTeeth"]
bike["calculateGearRatio"]()
虽然需要更多的输入,但方括号表示法有两个好处。您可以为属性或函数命名任何所需的名称,并且由于它是字符串,因此可以通过变量传递属性或函数名称并进行调用。
让我们通过重新构想changeGear
功能来了解这一点。现在,我们使用四个功能来定义前后齿轮的上下变速。在changeGear
函数中,我们根据String参数构造要调用的函数名称,然后调用它。
changeGear: function(frontOrRear, upOrDown) {
let shiftFunction = frontOrRear + upOrDown;
this[shiftFunction]();
},
frontUp: function(){
this.frontGearIndex += 1;
},
frontDown: function(){
this.frontGearIndex -= 1;
},
rearUp: function(){
this.rearGearIndex += 1;
},
rearDown: function(){
this.rearGearIndex -= 1;
}
将它们添加到我们的自行车对象中,我们可以在工作中看到它们。
console.log(bike.calculateGearRatio()); // 2.727272727
//Calls the frontUp() function
bike.changeGear("front", "Up");
console.log(bike.calculateGearRatio()); // 4.090909091
//calls the rearUp() function
bike.changeGear("rear", "Up");
console.log(bike.calculateGearRatio()); // 3.461538461
对象可变性
除了用于定义对象的不同语法外,JavaScript对象还有另一个关键原理:可变性。
JavaScript中的对象是可变的,这意味着如果您想要修改对象的形状,则可以。
让我们来看看bike
我们创建的对象。例如,我们可以添加一个新的属性或函数。
bike.isTandem = true;
bike.popAWheelie = function() {
…
};
即使您可能无法访问最初定义对象的代码,也可以在将对象保存在内存中后修改其形状。不过,重要的一点是,只有一个对象实例发生了变化。让我们回顾一下我们的Bike
构造函数:
const bike1 = new Bike();
const bike2 = new Bike();
bike1.isTandem = true;
console.log(bike1.isTandem); // true
console.log(bike2.isTandem); // undefined
如果您希望多个对象共享相同的属性或方法,则有一个继承模型。让我们看看。
对象与继承
尽管没有古典语言定义的类,JavaScript仍具有一个继承模型,称为原型继承。
实际上,原型是另一个对象。它位于内存中,并定义其他对象共享相同原型时所继承的属性或函数。
传统上,JavaScript对象通过共享相同的构造函数来共享相同的原型。记住Bike
构造函数。我们将changeGear
函数分配给prototype
。
function Bike(gears, startGear) {
this.gears = gears;
this.currentGear = startGear;
}
Bike.prototype.changeGear = function(direction, changeBy) {
if (direction === 'up') {
this.currentGear += changeBy;
} else {
this.currentGear -= changeBy;
}
}
这样,从中创建的每个对象都会Bike
继承该changeGear
函数。
您还可以使用原型实现多级继承。它被称为原型链。使用构造函数来实现原型链非常复杂,并且需要大量样板代码。它也超出了本模块的范围。您需要知道的是,为了解决原型链的复杂性,ECMA为实现继承的更直接的语法制定了一个标准:class
语法。
类和JavaScript
如果您阅读“类”一词并感到温暖而模糊,以为您正在寻找可以创建基于类的真正继承的东西,请准备感到失望。尽管如此,class
JavaScript中的关键字还是一个不错的语法糖,可以使用构造函数来解决原型继承的复杂性。在幕后,引擎仍在使用,Object.create
并且没有类(在面向对象的意义上),只是内存中的原型对象是实际的继承源。
好消息是,它确实从Java或C#中读取了很多类似的代码,并且需要考虑一些JavaScript特定的内容。
注意
当由Lightning Web Components使用时,包括类语法的多级原型链超出了此模块。有关使用JavaScript对象的较新功能的更多详细信息,请参见本单元末尾的资源链接。我们强烈建议您在本教程中使用其他 模块,即Modern JavaScript Development,该模块在Classes中有一个完整的单元
尽管我们在这里不会深入探讨JavaScript类的细节,但出于学术目的,很高兴看到使用类语法实现的bike对象的版本。
class Bike {
constructor(gears, startGear){
this.gears = gears;
this.currentGear = startGear;
}
changeGear(direction, changeBy) {
if (direction === 'up') {
this.currentGear += changeBy;
} else {
this.currentGear -= changeBy;
}
}
}
const bike = new Bike(10, 5);
console.log(bike.currentGear); // 5
bike.changeGear('up', 2);
console.log(bike.currentGear); // 7
如您所见,语法看起来更像Java或Apex中的类。明显的区别是,构造函数始终为命名constructor
。一个重要的功能是,函数和属性自动属于原型链,而不必直接引用Object.prototype。这也简化了创建多级原型继承的过程。
闪电Web组件和对象
本单元的几个部分与开发Lightning Web Components有关,包括我们讨论的一些语法以及原型链。
类和闪电Web组件
闪电Web组件利用了JavaScript的许多现代改进,最明显的是使用了类语法。组件通常由JavaScript类定义,该类扩展了另一个名为LightningElement的类。看起来是这样的:
import { LightningElement } from lwc;
export default class MyComponent extends LightningElement {
myProperty;
myFunction() {
console.log(this.myProperty);
}
}
Lightning Web组件的功能在JavaScript类中定义。此示例还使用了一些关于模块(import
和export
)尚未涉及的语法。
论对象文字
在本模块的某些示例中,为了学习对象的工作方式,我们在对象文字中声明了函数。请注意,这不是现代JavaScript中推荐的做法。对象文字是创建临时数据结构以在JavaScript程序的功能部分之间传递数据的一种好方法,但是您应避免在对象文字中定义函数。