新闻资讯

当前位置:新萄京娱乐场手机版 > 新闻资讯 > 原文出处

原文出处

来源:http://www.chrisproduction.com 作者:新萄京娱乐场手机版 时间:2019-10-14 02:15

浓重解读 JavaScript 中的面向对象编制程序

2017/07/07 · JavaScript · 面向对象

原稿出处: 景庄   

面向对象编制程序是用抽象格局开创基于现实世界模型的一种编制程序形式,首要不外乎模块化、多态、和包裹二种技艺。
对 JavaScript 来讲,当中央是支撑面向对象的,同期它也提供了苍劲灵活的基于原型的面向对象编程才具。
正文将会深远的研讨关于使用 JavaScript 举办面向对象编制程序的部分主导基础知识,包涵对象的创始,承袭机制,
终极还有也许会轻易的牵线怎么着依靠 ES6 提供的新的类机制重写古板的JavaScript面向对象代码。

面向对象的多少个概念

在步向正题前,先驾驭古板的面向对象编制程序(举例Java)中常会波及到的概念,大概能够包含:

  • 类:定义对象的特色。它是指标的性能和艺术的沙盘定义。
  • 目的(或称实例):类的多个实例。
  • 个性:对象的性状,比方颜色、尺寸等。
  • 方式:对象的行为,比如行走、说话等。
  • 构造函数:对象起先化的瞬间被调用的秘籍。
  • 后续:子类能够持续父类的风味。比方,猫承接了动物的平常本性。
  • 卷入:一种把数据和血脉相通的法子绑定在共同使用的办法。
  • 泛泛:结合复杂的接续、方法、属性的目标能够模拟现实的模子。
  • 多态:分歧的类能够定义同样的方式或性质。

在 JavaScript 的面向对象编制程序中山大学约也包蕴这一个。可是在称得上上可能稍有两样,比如,JavaScript 中从不原生的“类”的定义,
而只有对象的定义。由此,随着你认识的递进,我们会混用对象、实例、构造函数等概念。

对象(类)的创建

在JavaScript中,大家管见所及能够运用构造函数来创设特定项指标目的。诸如 Object 和 Array 那样的原生构造函数,在运作时会自动出现在推行境况中。别的,我们也得以创造自定义的构造函数。举个例子:

JavaScript

function Person(name, age, job) { this.name = name; this.age = age; this.job = job; } var person1 = new Person('Weiwei', 27, 'Student'); var person2 = new Person('Lily', 25, 'Doctor');

1
2
3
4
5
6
7
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
var person1 = new Person('Weiwei', 27, 'Student');
var person2 = new Person('Lily', 25, 'Doctor');

根据规矩,构造函数始终都应有以三个大写字母开始(和Java中定义的类同样),普通函数则小写字母初步。
要创建 Person 的新实例,必需采取 new 操作符。
以这种方法调用构造函数实际上会经历以下4个步骤:

  1. 创立二个新目的(实例)
  2. 将构造函数的功能域赋给新指标(也正是重设了this的指向,this就对准了那几个新对象)
  3. 推行构造函数中的代码(为这些新对象加多属性)
  4. 归来新对象

在上头的例子中,大家创立了 Person 的三个实例 person1person2
那四个指标暗许都有三个 constructor 属性,该属性指向它们的组织函数 Person,约等于说:

JavaScript

console.log(person1.constructor == Person); //true console.log(person2.constructor == Person); //true

1
2
console.log(person1.constructor == Person);  //true
console.log(person2.constructor == Person);  //true

自定义对象的档次检查评定

大家得以行使instanceof操作符实行项目检查评定。大家成立的享有目的既是Object的实例,同不经常常间也是Person的实例。
因为具备的对象都再三再四自Object

JavaScript

console.log(person1 instanceof Object); //true console.log(person1 instanceof Person); //true console.log(person2 instanceof Object); //true console.log(person2 instanceof Person); //true

1
2
3
4
console.log(person1 instanceof Object);  //true
console.log(person1 instanceof Person);  //true
console.log(person2 instanceof Object);  //true
console.log(person2 instanceof Person);  //true

构造函数的难题

我们不提议在构造函数中一直定义方法,假若这么做的话,各样方法都要在每个实例上再度创建三次,那将丰盛损耗质量。
——不要忘了,ECMAScript中的函数是指标,每定义二个函数,也就实例化了二个对象。

幸运的是,在ECMAScript中,大家得以重视原型对象来缓和那几个主题素材。

依附于原型格局定义对象的格局

大家创造的种种函数都有三个prototype属性,这性格格是多个指南针,指向该函数的原型对象
该指标包括了由特定项指标怀有实例分享的性质和方法。也便是说,大家得以采取原型对象来让具有目的实例共享它所包括的品质和格局。

JavaScript

function Person(name, age, job) { this.name = name; this.age = age; this.job = job; } // 通过原型形式来足够全数实例分享的点子 // sayName() 方法将会被Person的全部实例共享,而幸免了重复创制Person.prototype.sayName = function () { console.log(this.name); }; var person1 = new Person('Weiwei', 27, 'Student'); var person2 = new Person('Lily', 25, 'Doctor'); console.log(person1.sayName === person2.sayName); // true person1.sayName(); // Weiwei person2.sayName(); // Lily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
// 通过原型模式来添加所有实例共享的方法
// sayName() 方法将会被Person的所有实例共享,而避免了重复创建
Person.prototype.sayName = function () {
  console.log(this.name);
};
var person1 = new Person('Weiwei', 27, 'Student');
var person2 = new Person('Lily', 25, 'Doctor');
console.log(person1.sayName === person2.sayName); // true
person1.sayName(); // Weiwei
person2.sayName(); // Lily

正如上边的代码所示,通过原型情势定义的点子sayName()为持有的实例所分享。也便是,
person1person2做客的是同三个sayName()函数。一样的,公共性质也足以运用原型情势张开定义。例如:

JavaScript

function Chinese (name) { this.name = name; } Chinese.prototype.country = 'China'; // 公共性质,全部实例分享

1
2
3
4
function Chinese (name) {
    this.name = name;
}
Chinese.prototype.country = 'China'; // 公共属性,所有实例共享

当我们new Person()时,返回的Person实例会结合构造函数中定义的性质、行为和原型中定义的习性、行为,
转移最后属于Person实例的性质和作为。

构造函数中定义的属性和作为的优先级要比原型中定义的性质和行事的预先级高,假诺构造函数和原型中定义了同名的习性或作为,
构造函数中的属性或作为会覆盖原型中的同名的习性或行为。

原型对象

现在大家来深入的掌握一下怎么是原型对象。

若果创建了三个新函数,就能够基于一组特定的法则为该函数创制四个prototype品质,那个性情指向函数的原型对象。
在暗中同意情形下,全体原型对象都会活动获取叁个constructor个性,这么些性情蕴含贰个对准prototype特性所在函数的指针。
也正是说:Person.prototype.constructor指向Person构造函数。

创办了自定义的构造函数之后,其原型对象暗许只会获得constructor天性;至于其余艺术,则都以从Object后续而来的。
当调用构造函数创造贰个新实例后,该实例之少将包括二个指针(内部属性),指向构造函数的原型对象。ES5中称那一个指针为[[Prototype]]
在Firefox、Safari和Chrome在每种对象上都协理多天性质__proto__(近些日子已被吐弃);而在任何达成中,这一个天性对台本则是全然不可以看到的。
要注意,以此链接存在于实例与构造函数的原型对象之间,实际不是实例与构造函数之间

那三者关系的暗中提示图如下:

图片 1

上海教室展现了Person构造函数、Person的原型对象以致Person幸存的四个实例之间的关系。

  • Person.prototype针对了原型对象
  • Person.prototype.constructor又指回了Person构造函数
  • Person的各种实例person1person2都包蕴三个之中属性(常常为__proto__),person1.__proto__person2.__proto__本着了原型对象

追寻对象属性

从上海体育地方大家开采,纵然Person的七个实例都不蕴涵属性和章程,但大家却能够调用person1.sayName()
这是因此搜索对象属性的长河来促成的。

  1. 查找首先从对象实例自个儿伊始(实例person1sayName属性吗?——没有)
  2. 若是没找到,则持续查找指针指向的原型对象person1.__proto__sayName属性吗?——有)

那也是几个指标实例分享原型所保存的属性和章程的基本原理。

瞩目,假如大家在目的的实例中重写了有些原型中已存在的属性,则该实例属性会屏蔽原型中的这么些属性。
那会儿,能够运用delete操作符删除实例上的习性。

Object.getPrototypeOf()

根据ECMAScript标准,someObject.[[Prototype]] 符号是用以指使 someObject 的原型。
那几个等同于 JavaScript 的 __proto__ 属性(现已弃用,因为它不是正经)。
从ECMAScript 5开始, [[Prototype]] 可以用Object.getPrototypeOf()Object.setPrototypeOf()寻访器来访谈。

其中Object.getPrototypeOf()在颇有帮衬的贯彻中,那一个艺术重返[[Prototype]]的值。例如:

JavaScript

person1.__proto__ === Object.getPrototypeOf(person1); // true Object.getPrototypeOf(person1) === Person.prototype; // true

1
2
person1.__proto__ === Object.getPrototypeOf(person1); // true
Object.getPrototypeOf(person1) === Person.prototype; // true

也正是说,Object.getPrototypeOf(p1)回来的目的实际就是其一指标的原型。
本条方法的宽容性请参见该链接)。

Object.keys()

要博得对象上全部可枚举的实例属性,能够采用ES5中的Object.keys()方法。例如:

JavaScript

Object.keys(p1); // ["name", "age", "job"]

1
Object.keys(p1); // ["name", "age", "job"]

另外,倘让你想要获得全体实例属性,无论它是否可枚举,都可以使用Object.getOwnPropertyName()方法。

更简短的原型语法

在地点的代码中,倘若大家要增加原型属性和方法,就要重复的敲一次Person.prototype。为了减弱那一个重复的长河,
更广大的做法是用二个包罗全部属性和章程的靶子字面量来重写整个原型对象。
参谋资料。

JavaScript

function Person(name, age, job) { this.name = name; this.age = age; this.job = job; } // 重写整个原型对象 Person.prototype = { // 这里不可不要双重将构造函数指回Person构造函数,不然会指向这几个新创设的对象 constructor: Person, // Attention! sayName: function () { console.log(this.name); } }; var person1 = new Person('Weiwei', 27, 'Student'); var person2 = new Person('Lily', 25, 'Doctor'); console.log(person1.sayName === person2.sayName); // true person1.sayName(); // Weiwei person2.sayName(); // Lily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
// 重写整个原型对象
Person.prototype = {
  
  // 这里务必要重新将构造函数指回Person构造函数,否则会指向这个新创建的对象
  constructor: Person, // Attention!
  sayName: function () {
    console.log(this.name);
  }
};
var person1 = new Person('Weiwei', 27, 'Student');
var person2 = new Person('Lily', 25, 'Doctor');
console.log(person1.sayName === person2.sayName); // true
person1.sayName();  // Weiwei
person2.sayName();  // Lily

在上边的代码中特意包罗了三个constructor性子,并将它的值设置为Person,进而确定保障了经过该属性可以访问到相符的值。
留神,以这种办法重设constructor品质会形成它的[[Enumerable]]特征设置为true。暗中认可情形下,原生的constructor质量是不可计数的。
你能够动用Object.defineProperty()

JavaScript

// 重设构造函数,只适用于ES5相当的浏览器 Object.defineProperty(Person.prototype, "constructor", { enumerable: false, value: Person });

1
2
3
4
5
// 重设构造函数,只适用于ES5兼容的浏览器
Object.defineProperty(Person.prototype, "constructor", {
  enumerable: false,
  value: Person
});

构成使用构造函数方式和原型形式

创立自定义类型的最广大方法,正是组成使用构造函数格局与原型方式。构造函数情势用于定义实例属性,
而原型形式用于定义方法和分享的天性。结果,种种实例都会有温馨的一份实例属性的别本,但还要又分享着对方的援用,
最大限度的节约了内部存储器。

继承

多数的面向对象语言都支持三种持续格局:接口承袭和贯彻一而再。ECMAScript只援救落到实处三番五次,何况其实现持续首要依附原型链来达成。

眼前大家领会,JavaScript中实例的质量和行为是由构造函数和原型两部分联合构成的。倘使大家想让Child继承Father
那么我们就须求把Father构造函数和原型中属性和作为全体传给Child的构造函数和原型。

原型链承继

行使原型链作为完毕再三再四的大旨情想是:利用原型让五个援用类型承接另三个援引类型的性质和方式。首先大家先想起一些基本概念:

  • 每一个构造函数皆有七个原型对象(prototype
  • 原型对象包涵五个对准构造函数的指针(constructor
  • 实例都带有叁个对准原型对象的中间指针([[Prototype]]

万一大家让原型对象等于另贰个类型的完毕,结果会怎么?显著,那会儿的原型对象将包括贰个针对另一个原型的指针
对应的,另二个原型中也蕴藏着叁个针对另一个构造函数的指针。尽管另三个原型又是另二个品种的实例,那么上述提到照旧创建,
这么稀少递进,就组成了实例与原型的链条。
更详尽的剧情能够参照他事他说加以考察本条链接。
先看四个粗略的例子,它身体力行了利用原型链完结三番五次的核心框架:

JavaScript

function Father () { this.fatherValue = true; } Father.prototype.getFatherValue = function () { console.log(this.fatherValue); }; function Child () { this.childValue = false; } // 达成持续:承接自Father Child.prototype = new Father(); Child.prototype.getChildValue = function () { console.log(this.childValue); }; var instance = new Child(); instance.getFatherValue(); // true instance.getChildValue(); // false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Father () {
  this.fatherValue = true;
}
Father.prototype.getFatherValue = function () {
  console.log(this.fatherValue);
};
function Child () {
  this.childValue = false;
}
// 实现继承:继承自Father
Child.prototype = new Father();
Child.prototype.getChildValue = function () {
  console.log(this.childValue);
};
var instance = new Child();
instance.getFatherValue(); // true
instance.getChildValue();  // false

在上边的代码中,原型链承接的主导语句是Child.prototype = new Father(),它实现了ChildFather的继承,
而继续是因此创制Father的实例,并将该实例赋给Child.prototype实现的。

金镶玉裹福禄双全的实质是重写原型对象,代之以一个新品类的实例。也便是说,原本存在于Father的实例中的全数属性和章程,
当今也存在于Child.prototype中了。

本条事例中的实例以致构造函数和原型之间的关联如下图所示:

图片 2

在上头的代码中,大家平昔不采纳Child暗许提供的原型,而是给它换了一个新原型;那么些新原型正是Father的实例。
于是,新原型不止抱有了作为五个Father的实例所全数的全部属性和方法。何况其里面还会有三个指针[[Prototype]],指向了Father的原型。

  • instance指向Child的原型对象
  • Child的原型对象指向Father的原型对象
  • getFatherValue()措施照旧还在Father.prototype
  • 但是,fatherValue则位于Child.prototype
  • instance.constructor明日针对的是Father

因为fatherValue是二个实例属性,而getFatherValue()则是叁个原型方法。既然Child.prototype现在是Father的实例,
那么fatherValue当然就位于该实例中。

经过落到实处原型链,本质上扩展了本章后面介绍的原型寻觅机制。举个例子,instance.getFatherValue()会经历多个寻找步骤:

  1. 探究实例
  2. 搜索Child.prototype
  3. 搜索Father.prototype

别忘了Object

具备的函数都默许原型都以Object的实例,因而暗中认可原型都会蕴藏二个里边指针[[Prototype]],指向Object.prototype
那也多亏拥有自定义类型都会继续toString()valueOf()等默许方法的根本原因。所以,
大家说地方例子呈现的原型链中还相应包括此外一个卫冕档期的顺序。关于Object的越来越多内容,可以参照那篇博客。

也正是说,Child继承了Father,而Father继承了Object。当调用了instance.toString()时,
实质上调用的是保存在Object.prototype中的那么些情势。

原型链承继的主题素材

率先是各种,必供给先一连父类,然后为子类增加新章程。

其次,使用原型链完毕持续时,不可能利用对象字面量创立原型方法。因为那样做就能够重写原型链,如下边包车型地铁例证所示:

JavaScript

function Father () { this.fatherValue = true; } Father.prototype.getFatherValue = function () { console.log(this.fatherValue); }; function Child () { this.childValue = false; } // 继承了Father // 此时的原型链为 Child -> Father -> Object Child.prototype = new Father(); // 使用字面量增多新章程,会产生上一行代码无效 // 此时我们思念的原型链被隔断,而是成为 Child -> Object // 所以大家不引入这么写了 Child.prototype = { getChildValue: function () { console.log(this.childValue); } }; var instance = new Child(); instance.getChildValue(); // false instance.getFatherValue(); // error!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Father () {
  this.fatherValue = true;
}
Father.prototype.getFatherValue = function () {
  console.log(this.fatherValue);
};
function Child () {
  this.childValue = false;
}
// 继承了Father
// 此时的原型链为 Child -> Father -> Object
Child.prototype = new Father();
// 使用字面量添加新方法,会导致上一行代码无效
// 此时我们设想的原型链被切断,而是变成 Child -> Object
// 所以我们不推荐这么写了
Child.prototype = {
  getChildValue: function () {
    console.log(this.childValue);
  }
};
var instance = new Child();
instance.getChildValue();  // false
instance.getFatherValue(); // error!

在地方的代码中,大家总是一回修改了Child.prototype的值。由于现行反革命的原型富含的是三个Object的实例,
而非Father的实例,由此大家着想中的原型链已经被隔开分离——ChildFather中间已经远非关系了。

最后,在创设子类型的实例时,不可能向超类型的构造函数中传送参数。实际上,应该算得未有艺术在不影响全体目的实例的境况下,
给超类型的构造函数字传送递参数。由此,大家相当少单独使用原型链。

借用构造函数传承

借用构造函数(constructor stealing)的宗旨境维如下:即在子类构造函数的内部调用超类型构造函数。

JavaScript

function Father (name) { this.name = name; this.colors = ['red', 'blue', 'green']; } function Child (name) { // 承接了Father,同一时候传递了参数 // 之所以如此做,是为着博取Father构造函数中的全数属性和艺术 // 之所以用call,是为了改进Father内部this的针对 Father.call(this, name); } var instance1 = new Child("weiwei"); instance1.colors.push('black'); console.log(instance1.colors); // [ 'red', 'blue', 'green', 'black' ] console.log(instance1.name); // weiwei var instance2 = new Child("lily"); console.log(instance2.colors); // [ 'red', 'blue', 'green' ] console.log(instance2.name); // lily

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function Father (name) {
  this.name = name;
  this.colors = ['red', 'blue', 'green'];
}
function Child (name) {
  // 继承了Father,同时传递了参数
  // 之所以这么做,是为了获得Father构造函数中的所有属性和方法
  // 之所以用call,是为了修正Father内部this的指向
  Father.call(this, name);
}
var instance1 = new Child("weiwei");
instance1.colors.push('black');
console.log(instance1.colors); // [ 'red', 'blue', 'green', 'black' ]
console.log(instance1.name); // weiwei
var instance2 = new Child("lily");
console.log(instance2.colors); // [ 'red', 'blue', 'green' ]
console.log(instance2.name); // lily

为了保证Father构造函数不会重写子类型的性能,能够在调用超类型构造函数后,再增加应该在子类型中定义的性子。

借用构造函数的劣势

同构造函数一样,不能够完结形式的复用(全体的方式会被重复创造一份)。

结合使用原型链和借用构造函数

平常,大家会组成使用原型链承袭和借用构造函数来兑现一而再。也等于说,使用原型链完结对原型属性和措施的接续,
而由此借用构造函数来兑现对实例属性的接二连三。那样,既通过在原型上定义方法达成了函数复用,又能够确定保障每个实例都有它和谐的天性。
咱俩改动最先的例子如下:

JavaScript

// 父类构造函数 function Person (name, age, job) { this.name = name; this.age = age; this.job = job; } // 父类方法 Person.prototype.sayName = function () { console.log(this.name); }; // -------------- // 子类构造函数 function Student (name, age, job, school) { // 承袭父类的享有实例属性(得到父类构造函数中的属性) Person.call(this, name, age, job); this.school = school; // 增添新的子类属性 } // 承接父类的原型方法(获得父类原型链上的属性和情势) Student.prototype = new Person(); // 新扩大的子类方法 Student.prototype.saySchool = function () { console.log(this.school); }; var person1 = new Person('Weiwei', 27, 'Student'); var student1 = new Student('Lily', 25, 'Doctor', "Southeast University"); console.log(person1.sayName === student1.sayName); // true person1.sayName(); // Weiwei student1.sayName(); // Lilystudent1.saySchool(); // Southeast University

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 父类构造函数
function Person (name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
}
// 父类方法
Person.prototype.sayName = function () {
  console.log(this.name);
};
// --------------
// 子类构造函数
function Student (name, age, job, school) {
  // 继承父类的所有实例属性(获得父类构造函数中的属性)
  Person.call(this, name, age, job);
  this.school = school; // 添加新的子类属性
}
// 继承父类的原型方法(获得父类原型链上的属性和方法)
Student.prototype = new Person();
// 新增的子类方法
Student.prototype.saySchool = function () {
  console.log(this.school);
};
var person1 = new Person('Weiwei', 27, 'Student');
var student1 = new Student('Lily', 25, 'Doctor', "Southeast University");
console.log(person1.sayName === student1.sayName); // true
person1.sayName();  // Weiwei
student1.sayName(); // Lily
student1.saySchool(); // Southeast University

结缘集成幸免了原型链和借用构造函数的短处,融合了它们的独到之处,成为了JavaScript中最常用的持续形式。
而且,instanceofisPropertyOf()也能够用于识别基于组合承袭创造的对象。

整合承继的立异版:使用Object.create()

在上边,大家后续父类的原型方法应用的是Student.prototype = new Person()
这样做有大多的难点。
革新措施是采纳ES5中新添的Object.create()。能够调用这一个艺术来创立三个新对象。新对象的原型就是调用create()办法传入的率先个参数:

JavaScript

Student.prototype = Object.create(Person.prototype); console.log(Student.prototype.constructor); // [Function: Person] // 设置 constructor 属性指向 Student Student.prototype.constructor = Student;

1
2
3
4
Student.prototype = Object.create(Person.prototype);
console.log(Student.prototype.constructor); // [Function: Person]
// 设置 constructor 属性指向 Student
Student.prototype.constructor = Student;

详细用法能够参谋文书档案。
关于Object.create()的兑现,大家得以参见一个简练的polyfill:

JavaScript

function createObject(proto) { function F() { } F.prototype = proto; return new F(); } // Usage: Student.prototype = createObject(Person.prototype);

1
2
3
4
5
6
7
function createObject(proto) {
    function F() { }
    F.prototype = proto;
    return new F();
}
// Usage:
Student.prototype = createObject(Person.prototype);

从精神上讲,createObject()对传播在那之中的靶子施行了贰回浅复制。

ES6中的面向对象语法

ES6中引进了一套新的关键字用来贯彻class。
但它并非映入了一种新的面向对象承接情势。JavaScript仍旧是基于原型的,那几个新的首要字归纳class、
constructor、
static、
extends、
和super。

class重大字可是是提供了一种在本文中所研究的基于原型方式和构造器格局的面向对象的接轨格局的语法糖(syntactic sugar)

对后面包车型客车代码修改如下:

JavaScript

'use strict'; class Person { constructor (name, age, job) { this.name = name; this.age = age; this.job = job; } sayName () { console.log(this.name); } } class Student extends Person { constructor (name, age, school) { super(name, age, 'Student'); this.school = school; } saySchool () { console.log(this.school); } } var stu1 = new Student('weiwei', 20, 'Southeast University'); var stu2 = new Student('lily', 22, 'Nanjing University'); stu1.sayName(); // weiwei stu1.saySchool(); // Southeast University stu2.sayName(); // lily stu2.saySchool(); // Nanjing University

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
'use strict';
class Person {
  constructor (name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
  }
  sayName () {
    console.log(this.name);
  }
}
class Student extends Person {
  constructor (name, age, school) {
    super(name, age, 'Student');
    this.school = school;
  }
  saySchool () {
    console.log(this.school);
  }
}
var stu1 = new Student('weiwei', 20, 'Southeast University');
var stu2 = new Student('lily', 22, 'Nanjing University');
stu1.sayName(); // weiwei
stu1.saySchool(); // Southeast University
stu2.sayName(); // lily
stu2.saySchool(); // Nanjing University

类:class

是JavaScript中幸存基于原型的继续的语法糖。ES6中的并非一种新的创制对象的方法,只不过是一种“特殊的函数”,
据此也饱含类表明式和类声明,
但须要在意的是,与函数评释分歧的是,类注明不会被提升。
参照链接

类构造器:constructor

constructor()方法是有一种奇特的和class手拉手用于创设和起头化对象的艺术。注意,在ES6类中不得不有一个称谓为constructor的方法,
再不会报错。在constructor()措施中得以调用super重中之重字调用父类构造器。就算你从未点名叁个构造器方法,
类会自动使用四个暗许的构造器。参照链接

类的静态方法:static

静态方法正是能够直接利用类名调用的章程,而不必要对类实行实例化,当然实例化后的类也心余力绌调用静态方法。
静态方法常被用来创立应用的工具函数。参照链接

接轨父类:extends

extends着重字能够用来后续父类。使用extends能够增加三个放置的对象(如Date),也得以是自定义对象,也许是null

关键字:super

super根本字用于调用父对象上的函数。
super.propsuper[expr]表明式在类和对象字面量中的任何措施定义中都有效。

JavaScript

super([arguments]); // 调用父类构造器 super.functionOnParent([arguments]); // 调用父类中的方法

1
2
super([arguments]); // 调用父类构造器
super.functionOnParent([arguments]); // 调用父类中的方法

一旦是在类的构造器中,供给在this重在字在此以前使用。参谋链接

小结

本文对JavaScript的面向对象机制进行了较为深远的解读,尤其是构造函数和原型链格局完成目的的始建、承袭、以致实例化。
其他,本文还简单介绍了如在ES6中编辑面向对象代码。

References

  1. 详解Javascript中的Object对象
  2. new操作符
  3. JavaScript面向对象简单介绍
  4. Object.create()
  5. 一而再与原型链
  6. Understanding the prototype property in JavaScript

    1 赞 8 收藏 评论

图片 3

本文由新萄京娱乐场手机版发布于新闻资讯,转载请注明出处:原文出处

关键词: