跳至正文
首页 » 博客 » Simplifying Objects, Inheritance and prototype in JavaScript

Simplifying Objects, Inheritance and prototype in JavaScript

虽然JavaScript是一种无类语言,但它支持对象创建,覆盖属性/方法和继承。在这篇文章中,我们将探讨对象创建和继承的概念。

在JavaScript中,可以通过三种可能的方式创建对象:

  1. 一个对象作为文字
  2. 使用函数构造函数
  3. 使用Object.Create方法

对象作为文字

可以创建一个简单的对象学生-作为对象文字-如下所示:

var学生 = {name: "dj",年龄: 32,父亲: {        'name': 'Ram',        '职业': '服务'},主题: [{“物理”:标记: 89},{“化学” 名称:标记: 95}]};

上面我们创建了一个名为Student的对象。有三种类型的属性附加到学生: 简单的属性,如姓名和年龄,复杂的属性,如 “父亲”,和一个数组属性称为主题。我们可以读取如下所示的属性:

console.lo g(Student.Father.name);对于 (Student.主题中的var i) {console.log(Student.主题 [i].name);}

我们也可以有一个函数作为对象的属性,称为方法。因此,假设我们要将方法 “Speak” 附加到Student对象。我们可以添加Speak方法,如下面的清单所示。

var学生 = {name: "dj",年龄: 32,};Student.Speak = 函数 (消息) {    var finalMessage = this”曾说过:“ 留言;console.log(finalMessage);};学生。说 “我是最棒的”

在调用Speak函数作为方法时,我们将得到如下图所示的输出:

关于Speak方法有一些重要的要点需要记住:

  1. 属性可以随时添加到对象中; 属性也可以在对象创建后添加到对象中。例如,我们稍后将Speak属性添加到Student对象,而不是在创建对象时添加。
  2. 在对象的方法中,对象由值 “这个” 定义。这就是为什么我们能够在方法中g this.name打印学生姓名的原因。
  3. 调用一个函数作为方法被称为 “方法调用模式”

在上面的例子中,我们在对象 “Student” 上调用Speak方法。所以这个说话方法里面的值就是学生对象。

如果我们想在方法中传递一些其他对象作为 “这个” 的值,我们可以使用apply或call函数。例如,我们还有一个叫做父母的对象,

  1. 我们调用Speak方法的Student对象直接和值 “这个” 在Speak方法将是学生。
  2. 我们在Student对象的Speak方法中传递Parent作为 “此” 的值。我们正在使用apply函数来调用Student对象的Speak方法,并将父对象作为this的值传递。

我们可以执行上述任务,如下所示:

学生。说 “我是最棒的”var父级 = {    'name': 'Ram'}学生.说.申请 (家长, “我是最棒的”)

在运行时,我们将得到如下输出:

从输出中可以推断,第二行中的 “this” 的值是Parent,因此作为输出,我们为name的值获取Ram。

使用函数构造函数

创建对象的第二种方法是使用函数构造函数。当我们使用new运算符调用函数时,该函数将成为构造函数并返回新创建的对象。在函数构造函数中,当前对象由 “this” 表示。

职能人员 (姓名、年龄) {    这个 .name = name;    这个 .age = 年龄;    这个 .消息 = 函数 () {console.log(  );console.log (。姓名  "是"   。年龄  “岁!”);}};var person1 = 人员 (32“dj” );var person2 = 人员 (34“mj” );person1.message();person2.message();

在上面的清单中,我们使用new运算符调用Person函数,因此,Person函数作为函数构造函数,并返回一个保存在person1和person2中的新对象。然后,我们在person1和person2对象上调用message方法。

在运行上面的代码片段时,我们将得到如下图所示的输出:

在上面的输出中值得注意的一点是,每个对象都有自己的消息方法。在许多情况下,你可能不想要它。也许,您可能希望跨对象共享消息方法,并将 “此” 值设置为调用该方法的对象。这可以通过将消息方法附加到Person的原型来完成。

职能人员 (姓名、年龄) {    这个 .name = name;    这个 .age = 年龄;};Person.prototype.message = 函数 () {console.log(  );console.log (。姓名  "是"   。年龄  “岁!”);}var person1 = 人员 (33“dj” );var person2 = 人员 (34“mj” );person1.message();person2.message();

这里发生了什么?在执行上面的代码片段时,您会发现message方法没有为每个对象复制,它是Person构造函数的原型的一部分。运行上面的代码片段时,您将获得如下图所示的输出:

函数构造函数使我们能够在对象中拥有私有属性。我们可以通过两种可能的方式创建私有财产-

  1. 使用var而不是这个来创建属性
  2. 使用揭示模式。

可以使用var创建私有属性,如下面的清单所示-

职能人员 (姓名、年龄) {    var prvvar = "i m private"    这个 .name = name;    这个 .age = 年龄;};var person1 = 人员 (33“dj” );var a = person1.prvvar;console.log(a);

这里,Person函数之外的prvvar的期望值是未定义的。

创建私有变量的另一种方法是使用揭示模式。我们可以通过从构造函数显式返回公共属性和公共方法来创建私有属性,如下面的清单所示:

职能人员 (姓名、年龄) {    这个 .name = name;    这个 .age = 年龄;    返回 {pubvar: 这个名称 “is”年龄 “岁”}};var person1 = 人员 (33“dj” );var a = person1.pubvar;console.log(a);

让我们看看这里发生了什么。我们明确地返回pubvar作为公共财产。在上面的代码片段中,name和age属性成为私有变量,并且在Person函数之外访问它们将返回undefined。

继承在JavaScript

JavaScript支持基于原型的继承,而不是类,对象相互继承。在学习继承之前,让我们先看一下JavaScript中的原型。在JavaScript中,函数和对象的原型行为不同。

什么是原型?

每个函数都有一个prototype属性。让我们考虑一个函数如下:

函数foo (名称) {    这个 .名称 = 名称};var fooPro = foo.prototype;console.log(fooPro);

作为输出,我们将获得一个空对象作为函数的原型值。

函数原型是对象实例,它最终成为使用该函数构造函数创建的所有对象的原型。

让我们继续使用foo函数的new运算符创建对象。在下面的列表中,我们创建两个对象,然后打印两个对象的 __proto __value。

foo.prototype.age = 30var foobj1 = foo () “mj”var foobj2 = foo ("dj")console.log(fooobj1.__proto__);console.log(fooobj2.__proto__);if (fooobj1.__proto__ === foo.prototype) {console.log( "true" );}

你会发现两个对象的 __proto __ 值是相同的。还有一个重要的观察可能是 __proto __ 对象的值等于函数的原型值。预期的输出将如下图所示

通过查看上面的示例,我们可以说函数原型是一个对象实例,它将成为使用该函数作为构造函数创建的所有对象的原型。

另一方面,对象没有原型值,相反,他们有 __proto __value。让我们考虑下面的例子:

var foo = {};console.log(foo.prototype);console.log(foo.__proto__);

我们正在打印foo的原型值以及foo的 __proto __ 值。对于prototype值,JavaScript将返回undefined,而对于 __ proto __,它将返回一个空对象。预期的输出将如下图所示:

每个对象继承一个对象。对象 __proto __value设置为继承对象的对象实例。

使用 __proto __ 进行继承

关于JavaScript继承的一些要点如下

  1. JavaScript支持基于原型的继承
  2. 在JavaScript中,对象继承彼此
  3. 父对象也称为原型的子对象在JavaScript。
  4. 在JavaScript中,继承是通过 (对于对象) 特殊属性 __proto __
  5. 实现的

  6. 要访问属性,JavaScript首先搜索对象,如果找不到,则搜索对象的 __proto __ 属性中的对象。在现代浏览器中,__proto __ property也称为prototype属性。

让我们从两个非常简单的对象开始

var动物 = {吃: 真的,canRun: function () {“哟可以运行!” (console.log);}};var dog = {canbark: true};

这里我们有两个对象: 动物和狗。对象动物具有两个属性-eats和canRun。对象狗有一个属性: canBark。

让我们看看对象狗是如何继承对象动物的。使用 _proto __ 属性,dog可以继承animal,如下面的清单所示:

狗。__proto __ = 动物;console.log(dog.eats);dog.ca nRun();

通过将 __proto__ 属性设置为animal,我们将animal继承为dog。正如您在上面的示例中注意到的那样,现在在dog对象上,我们可以访问eats和canRun属性。

JavaScript解释器分两步搜索属性。

  1. 首先,它在当前对象中搜索属性。如果它找到它,它使用它。
  2. 如果它在当前对象中找不到属性,它将在对象的 __proto __ 值中搜索该属性,直到 __proto __ 值变为null。

使用 “这个” 继承

无论 __ proto __ 的值如何,JavaScript总是将当前对象赋值为 “this” 的值。为了理解它,让我们修改前一个对象,s动物和狗。

var动物 = {吃: 真的,canRun: function () {        这个 .isCute ="}};var dog = {canbark: true};

正如你所注意到的,我们有两个对象: 动物和狗。在animal对象的方法canRun中,我们正在创建一个属性isCute并将其附加到 “this” 或当前对象。让我们继续在狗中继承动物。

狗。__proto __ = 动物;dog.ca nRun();var标志 = dog.hasOwnProperty( "isCute" );console.log (标志);

正如你正确地注意到,使用hasOwnProperty() 方法,我检查isCute是否是狗对象的属性。我们将得到true的输出。之所以会发生这种情况,是因为在调用canRun() 方法之前,JavaScript将dog指定为 “此” 的值。

JavaScript方法hasOwnProperty() 对于对象自己的属性返回true,对于原型的属性返回false。在这种情况下,它将返回true,因为isCute已附加为dog对象的属性。

让我们再举一个例子来解释 “这个” 的值是如何分配的。在前面的示例中,我们使用 __proto __ 来创建继承。在这个例子中,我们将使用Object.create() 方法来克隆一个对象。在后面的文章中,我们将介绍更多关于Object.create() 的内容。

让我们考虑我们有一个对象foo,如下面的清单所示:

var foo = {c: 8,添加: 函数 () {        这个.这个c = 。c  1;}};

对象foo有两个属性,c和一个方法添加。在add方法中,c属性的值递增1。接下来,让我们通过使用object.create() 方法克隆object foo来创建另一个对象。

var koo = 对象。创建 (foo);koo.c = 99;koo.add();console.log(koo.c);

上面的代码片段发生了什么?我们通过克隆对象foo来创建对象koo。所以对象koo具有foo的所有属性。我们正在设置属性c的值,然后在koo对象上调用方法add。正如我们在前面的示例中讨论的那样,无论原型的值是什么,“this” 的值始终设置为调用方法中的点之前的对象。因此,在这种情况下,“this” 的值被设置为koo对象。上述代码段的预期输出将为100。

随着新的ECMA规范,__proto__ 正在贬值,所有浏览器都支持原型。我们可以使用原型而不是 __proto __ 来创建继承。请记住,原型仅适用于函数构造函数,并且在所有浏览器中都得到广泛支持。

让我们看看如何使用原型来创建继承。让我们从一个函数Employee开始,如下面的清单所示:

职能员工 (姓名) {    这个 .name = name;}变量e = 新员工 (“dj” );

我们使用new运算符调用Employee函数作为构造函数来创建对象e。在执行构造函数时,name属性的值设置为值dj。接下来,让我们继续创建另一个构造函数: SuperEmployee。

函数SuperEmployee(sal) {    这个 .sal = sal;}SuperEmployee.prototype = e;var se = 超级员工 (5000 );console.lo g(se.name);

SuperEmployee函数原型设置为对象实例e。SuperEmployee构造函数的对象实例将继承e对象实例的name属性。我们还可以设置SuperEmployee的原型,如下所示:

职能员工 (姓名) {    这个 .name = name;}Employee.prototype.age = 30函数SuperEmployee(sal) {    这个 .sal = sal;}SuperEmployee.prototype = Employee.prototype;var se = 超级员工 (5000 );console.log(se.age);

在上面的清单中,我们将SuperEmployee函数的原型值设置为Employee原型。这样,SuperEmployee将继承Employee原型的所有属性。

继承使用Object.create()

在JavaScript中,我们也可以使用object.create方法创建对象。我发现这是创建对象的最简单方法。

var foo = 对象。create( Object .prototype);foo.name =; "dj"foo.age = 33;console.lo g(foo.name);

在上面的代码片段中,我们创建了一个对象foo,然后动态添加了两个属性: name和age。“dj” 将是输出,如下图所示:

关于Object.create() 的一些要点如下:

  • 此方法有两个参数。第一个参数是要继承的对象的原型,并且是必需的参数。
  • 第二个参数是可选参数,并在新创建的对象中添加新属性。
  • 第一个参数可以为null,但在这种情况下,新对象将不会继承任何属性。
  • 要创建空对象,必须将object.prototype作为第一个参数传递。

我们可以使用Object.create() 来创建一个继承另一个对象实例的对象。例如,假设我们想在koo对象中继承foo对象。

var koo = 对象。创建 (foo);koo.grade = "a";console.lo g(koo.name);console.log(koo.age);console.log(koo.grade);

在创建koo对象时,我们在object.Create中传递foo对象。所以koo对象将继承foo对象的所有属性。JavaScript将复制foo对象,这样可以被分配为koo对象的原型值。

把它放在一起来创建一个简单的原型继承链

到目前为止,我们已经了解了函数构造函数、对象文字、 __proto __、prototype和object.create()。现在让我们把它们放在一起来创建一个帮助函数,它将接受两个对象并在它们之间创建一个继承。我们可以创建如下所示的函数:

var继承 = 函数 (child,parent) {child.prototype = 对象。创建 (parent.prototype);}

为了创建继承,我们将子级的原型设置为父级函数的原型。现在让我们继续创建一个简单的函数构造函数foo,并创建它的对象实例。

var foo = 函数 () {    这个 .name = "class foo";}foo.prototype.print = 函数 () {console.log(  .name);}var f = foo();f.print();

如果您正在进行讨论,您知道f是foo的对象实例,作为输出,我们将获得类foo的输出。接下来,让我们继续创建另一个函数fooChild,并使用我们上面创建的inherit函数从foo函数继承它。

var fooChild = 函数 () {    这个."foo child" 名称 =    这个 .姓 =“我是foo的孩子”}inherit(fooChild, foo);var fchild = 的fooChild();fchild.print();

在上面的代码片段中,我们在fooChild中继承foo,并在fooChild构造函数的对象实例fchild上调用foo的print方法。这将打印fooChild的name属性,如下图所示:

要打印surname属性,我们需要覆盖fooChild函数中的print方法,如下所示:

fooChild.prototype.print = 函数 () {foo.prototype.print.ca ll( 这个 );console.log(  .姓);}

重写后,当您在fooChild对象上调用print方法时,它将打印name和surname值。

通过这种方式,我们可以在JavScript中创建一个简单的继承链。把它们放在一起,继承链代码将如下所示:

var foo = 函数 () {    这个 .name = "class foo";}foo.prototype.print = 函数 () {console.log( this .name);}var f = foo();f.print();var fooChild = 函数 () {    这个."foo child" 名称 =    这个 .姓 =“我是foo的孩子”}inherit(fooChild, foo);var fchild = 的fooChild();fooChild.prototype.print = 函数 () {foo.prototype.print.ca ll( 这个 );console.log(  .姓);}fchild.print();

和预期的输出如下:

结论

在这篇文章中,我们从构造简单的对象开始,最后通过创建一个函数来在JavaScript中创建原型继承。我们在这篇文章中讨论了以下主题:

  • 对象文字
  • 函数构造函数
  • 揭示模式
  • 理解 “这个”
  • __proto __ 对象的属性
  • 原型值函数
  • 继承使用 __proto __ 和prototype
  • Object.create() 方法用于对象构造
  • 创建一个继承链

我希望你喜欢这篇文章,并发现它很有用。有什么要补充的吗?发表评论!感谢您的阅读 </p