Object-oriented JavaScript for beginners
先决条件: | 基本的计算机素养,对HTML和CSS的基本了解,熟悉JavaScript基础知识(请参见第一步和构建块 / a>)和OOJS基础知识(请参见对象简介)。 |
---|---|
目的: | 要理解面向对象编程背后的基本理论,这是如何与JavaScript(“一切都是一个对象")有关,以及如何创建构造函数和对象实例。 |
面向对象编程从10,000米
首先,让我们给出一个简单的,高级的面向对象编程(OOP)的视图。 我们说简单,因为OOP可以很快变得非常复杂,现在给它一个完全的治疗可能会混淆更多的帮助。 OOP的基本思想是,我们使用对象来模拟我们想要在程序中表示的现实世界中的事物,和/或提供一种简单的方法来访问否则难以或不可能使用的功能。
对象可以包含相关数据和代码,它们表示有关您尝试建模的信息,以及您希望它具有的功能或行为。 对象数据(通常也是函数)可以在一个对象包(它可以被给定一个特定的名称来引用,有时称为)中整齐地存储(官方单词封装 > namespace ),使其易于构造和访问; 对象也通常用作可以容易地通过网络发送的数据存储。
定义对象模板
让我们考虑一个简单的程序,显示学校的学生和教师的信息。 这里我们将一般来看看OOP理论,而不是在任何特定的编程语言的上下文中。
要开始此操作,我们可以从第一个对象文章返回到我们的Person对象类型,该文章定义了人员的通用数据和功能。 有很多东西你可以知道一个人(他们的地址,身高,鞋码,DNA个人资料,护照号码,重要的个性特征...),但在这种情况下,我们只感兴趣 显示他们的名字,年龄,性别和兴趣,我们也希望能够基于这些数据写一个简短的介绍,并让他们打招呼。 这被称为抽象 - 创建一个更复杂的事情的简单模型,它以一种很容易与我们程序的目的一起使用的方式表示其最重要的方面。
>
在一些OOP语言中,这个通用对象类型定义被称为类(JavaScript使用不同的机制和术语,如下所示) - 它实际上不是对象,而是一个 模板,定义对象应具有的特性。
创建实际对象
从我们的类中,我们可以创建对象实例 - 包含类中定义的数据和功能的对象。 从我们的Person类,我们现在可以创建一些实际的人:
:700px;">
当从类创建对象实例时,将运行类的构造函数来创建它。 从类创建对象实例的过程称为实例化 - 对象实例从类中实例化。
专业课
在这种情况下,我们不想要一般人 - 我们希望教师和学生,这两种更具体类型的人。 在OOP中,我们可以基于其他类创建新类 - 这些新的子类可用于继承其父类的数据和代码功能 strong>,因此您可以重用所有对象类型通用的功能,而不必重复它。 在类之间的功能不同时,您可以根据需要直接在其上定义特定功能。
:700px;">
这是非常有用的 - 教师和学生分享了许多常见的功能,如姓名,性别和年龄,所以只需要定义这些功能一次便利。 您还可以在不同的类中单独定义相同的功能,因为该功能的每个定义都将位于不同的命名空间中。 例如,学生的问候语可以是"Yo,I\'m [firstName]"(例如,
注意:对于多个对象类型实现相同功能的能力而言,多态性非常奇怪。 以防万一你想知道。
现在可以从子类创建对象实例。 例如:
; width:700px;">
在本文的其余部分,我们将开始研究如何在JavaScript中实现OOP理论。
构造函数和对象实例
有些人认为JavaScript不是一个真正的面向对象的语言 - 例如它没有用于创建像许多OO语言的类的 class
语句。 JavaScript使用称为构造函数的特殊函数来定义对象及其特征。 它们很有用,因为你会经常遇到你不知道你将要创建多少对象的情况; 构造函数提供了以有效方式创建任意数量对象的方法,根据需要将数据和函数附加到它们。
当从构造函数创建一个新的对象实例时,并不是所有的功能都被复制到像"经典"OO语言这样的新对象,而是通过一个称为原型链的引用链链接到该对象实例(参见 "/ webstart / Objects / Object_prototypes">对象原型)。 所以这不是真正的实例化,严格来说 - JavaScript使用不同的机制在对象之间共享功能。
注意:不是"经典OOP"不一定是坏事; 如上所述,OOP可以非常快速地得到非常复杂,JavaScript有一些不错的方法利用OO功能,而不必太深入。
让我们探索通过构造函数创建类并在JavaScript中从中创建对象实例。 首先,我们希望您创建一个新的本地副本 class ="external"> oojs.html 文件,我们在第一篇Objects文章中看到。
一个简单的例子
- Let's start by looking at how you could define a person with a normal function. Add this function below the existing code:
function createNewPerson(name) { var obj = {}; obj.name = name; obj.greeting = function () { alert('Hi! I\'m ' + this.name + '.'); } return obj; }
- You can now create a new person by calling this function — try the following lines in your browser's JavaScript console:
var salva = createNewPerson('salva'); salva.name; salva.greeting();
This works well enough, but it is a bit longwinded; if we know we want to create an object, why do we need to explicitly create a new empty object and return it? Fortunately JavaScript provides us with a handy shortcut, in the form of constructor functions — let's make one now! - Replace your previous function with the following:
function Person(name) { this.name = name; this.greeting = function() { alert('Hi! I\'m ' + this.name + '.'); }; }
构造函数是JavaScript的一个类的版本。 你会注意到它有一个所有的功能,你期望在一个函数,虽然它不返回任何东西或显式创建一个对象 - 它基本上只是定义属性和方法。 你会看到这里使用的 this
关键字 - 它基本上是说,无论何时创建这些对象实例之一,对象的 name
属性将等于 传递给构造函数调用的名称值, greeting()
方法将使用传递给构造函数调用的名称值。
注意:构造函数名称通常以大写字母开头 - 此约定用于使构造函数在代码中更易于识别。
那么我们如何调用构造函数来创建一些对象呢?
- Add the following lines below your previous code addition:
var person1 = new Person('Bob'); var person2 = new Person('Sarah');
- Save your code and reload it in the browser, and try entering the following lines into your text input:
person1.name person1.greeting() person2.name person2.greeting()
凉! 现在,您将看到页面上有两个新对象,每个对象都存储在不同的命名空间下 - 当您访问其属性和方法时,必须使用 person1
或 > person2
; 他们整齐地打包,使他们不会与其他功能冲突。 但是它们具有相同的 name
属性和 greeting()
方法。 注意,他们使用自己创建时分配给他们的 name
值; 这是为什么使用 this
非常重要的一个原因,所以他们将使用自己的值,而不是一些其他值。
让我们再看看构造函数调用:
var person1 = new Person('Bob'); var person2 = new Person('Sarah');
在每种情况下, new
关键字用于告诉浏览器我们要创建一个新的对象实例,后面跟着括号中包含其必需参数的函数名称,结果存储在变量中 - 非常类似于如何调用标准函数。 每个实例根据此定义创建:
function Person(name) { this.name = name; this.greeting = function() { alert('Hi! I\'m ' + this.name + '.'); }; }
创建新对象后, person1
和 person2
变量实际上包含以下对象:
{ name : 'Bob', greeting : function() { alert('Hi! I\'m ' + this.name + '.'); } } { name : 'Sarah', greeting : function() { alert('Hi! I\'m ' + this.name + '.'); } }
我们有效地说,因为实际上,功能仍然在类中定义,而不是在对象实例,而不是我们前面看到的对象字面量。
创建我们完成的构造函数
我们上面看到的例子只是一个简单的例子,让我们开始。 让我们开始创建我们的最终 Person()
构造函数。
- Remove the code you inserted so far, and add in this replacement constructor — this is exactly the same as the simple example in principle, with just a bit more complexity:
function Person(first, last, age, gender, interests) { this.name = { first, last }; this.age = age; this.gender = gender; this.interests = interests; this.bio = function() { alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); }; this.greeting = function() { alert('Hi! I\'m ' + this.name.first + '.'); }; };
- Now add in the following line below it, to create an object instance from it:
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
现在您将看到,您可以像访问我们定义的第一个对象一样访问属性和方法:
person1['age'] person1.interests[1] person1.bio() // etc.
注意:如果您无法使用此工具,请尝试将您的代码与我们的版本进行比较 - 请参阅 /javascript/oojs/introduction/oojs-class-finished.html"class ="external"> oojs-class-finished.html (也 -area / javascript / oojs / introduction / oojs-class-finished.html"class ="external">查看它正在运行)。
进一步练习
首先,尝试添加一些您自己的对象创建行,并尝试获取和设置生成的对象实例的成员。
此外,我们的 bio()
方法有一些问题 - 输出总是包括代词"He",即使你的人是女性,或一些其他首选的性别分类。 并且bio将只包括两个兴趣,即使更多的兴趣列在 interests
数组。 你能解决如何解决这个在类定义(构造函数)? 你可以把任何你喜欢的代码放在构造函数中(你可能需要一些条件和循环)。 考虑如何根据性别,以及取决于所列出的兴趣的数量是1,2还是多于2,句子应该结构不同。
注意:如果您遇到困难,我们提供了 -further-exercises.html"class ="external"> answer在我们的GitHub repo ( class-further-exercises.html"class ="external">看到它现场) - 尝试自己首先写它!
创建对象实例的其他方法
到目前为止,我们已经看到了两种创建对象实例的方法 - 声明对象字面值,并使用构造函数(参见上文)。
这些都是有意义的,但还有其他方法 - 我们希望让您熟悉这些,以防万一您在网络上的旅行中遇到它们。
Object()构造函数
首先,您可以使用 Object()
构造函数创建一个新对象。 是的,即使通用对象有一个构造函数,它生成一个空对象。
- Try entering this into your browser's JavaScript console:
var person1 = new Object();
- This stores an empty object in the
person1
variable. You can then add properties and methods to this object using dot or bracket notation as desired; try these examples:person1.name = 'Chris'; person1['age'] = 38; person1.greeting = function() { alert('Hi! I\'m ' + this.name + '.'); }
- You can also pass an object literal to the
Object()
constructor as a parameter, to prefill it with properties/methods. Try this:var person1 = new Object({ name : 'Chris', age : 38, greeting : function() { alert('Hi! I\'m ' + this.name + '.'); } });
使用create()方法
JavaScript有一个内置的方法 create()
a> ,它允许您基于现有对象创建新的对象实例。
- Try this in your JavaScript console:
var person2 = Object.create(person1);
- Now try these:
person2.name person2.greeting()
您将看到基于 person1
创建的 person2
- 它具有相同的属性和方法。 这是非常有用的,因为它允许你创建新的对象实例,而不需要定义一个构造函数。 缺点是 create()
不支持的浏览器早在构造函数(IE9,而不是IE8甚至之前),加上一些think构造函数给你的代码更多的顺序 - 你可以创建你的 构造函数在一个地方,然后根据需要创建实例,并清楚它们来自哪里。
但是,如果你不太担心支持真正旧的浏览器,并且你只需要一个对象的几个副本,创建一个构造函数可能是overkill的代码。 这取决于你喜欢什么。 有些人只是发现 create()
更容易理解和使用。
我们将在后面更详细地探讨 create()
的效果。
概要
本文提供了面向对象理论的简化视图 - 这不是全部的故事,但它给了我们在这里处理我们的想法。 此外,我们已经开始看看JavaScript如何与"经典OOP",如何使用构造函数在JavaScript中实现类以及生成对象实例的不同方式有所不同。
在下一篇文章中,我们将探讨JavaScript对象原型。