JavaScript言语不像面向对象的编程言语中有类的观点,所以也就没有类之间直接的继续,JavaScript中只要对象,运用函数模仿类,基于对象之间的原型链来完成继续关联,
ES6的语法中新增了class关键字,但也只是语法糖,内部照样经由过程函数和原型链来对类和继续举行完成。
1 原型链
1.1 原型链定义
JavaScript对象上都有一个内部指针[[Prototype]],指向它的原型对象,而原型对象的内部指针[[Prototype]]也指向它的原型对象,直到原型对象为null,如许构成的链条就称为原型链。
如许在接见对象的属性时,会如今自身的属性中查找,假如不存在则会到上一层原型对象中查找。
注重:
依据 ECMAScript 规范,someObject.[[Prototype]] 标记是用于指派 someObject 的原型。这个等同于 JavaScript 的 proto 属性(现已弃用)。从 ECMAScript 6 最先, [[Prototype]] 可以用Object.getPrototypeOf()和Object.setPrototypeOf()接见器来接见。
比方:
var obj2 = {
height: 170
}
var obj3 = {
name: 'obj3'
}
Object.setPrototypeOf(obj3, obj2);
console.log(obj3.height); // 170
var isproto = Object.getPrototypeOf(obj3) === obj2;
console.log(isproto); // true
1.2 差别要领建立对象与天生原型链
1.2.1 运用 Object.create 建立对象
ECMAScript 5 中引入了一个新要领:Object.create()。可以挪用这个要领来建立一个新对象。新对象的原型就是挪用 create 要领时传入的第一个参数。
比方:
var a = {a: 1};
// a ---> Object.prototype ---> null
var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (继续而来)
var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null
var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty); // undefined, 由于d没有继续Object.prototype
1.2.2 运用组织函数建立对象
在 JavaScript 中,组织函数实在就是一个平常的函数,平常函数名首字母大写。当运用 new 操作符 来作用这个函数时,它就可以被称为组织要领(组织函数)。
比方:
function Person (name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
sayName: function () {
console.log(this.name);
}
}
var person1 = new Person('yangyiliang', 23);
person1.sayName(); // yangyiliang
运用组织函数建立对象,阅历了以下三个关键步骤:
var temp = {}; //1 建立空对象
Person.call(temp, 'yangyiliang', 23); //2 以空对象为this实行组织函数
Object.setPrototypeOf(temp, Person.prototype); //3 将组织函数的prototype 设置为空对象的原型
return temp;
1.2.3 运用字面量要领建立对象
运用字面量要领建立的对象,依据对象的范例,他们的原型都邑指向响应JavaScript内置组织函数的prototype,和直接运用内置组织函数建立对象天生的原型链雷同,比方:
var o = {a: 1};
// o这个对象继续了Object.prototype上面的一切属性
// 所以可以如许运用 o.hasOwnProperty('a').
// hasOwnProperty 是Object.prototype的自身属性。
// Object.prototype的原型为null。
// 原型链以下:
// o ---> Object.prototype ---> null
var a = ["yo", "whadup", "?"];
// 数组都继续于Array.prototype
// (indexOf, forEach等要领都是从它继续而来).
// 原型链以下:
// a ---> Array.prototype ---> Object.prototype ---> null
function f(){
return 2;
}
// 函数都继续于Function.prototype
// (call, bind等要领都是从它继续而来):
// f ---> Function.prototype ---> Object.prototype ---> null
2 继续
在面向对象的言语当中,继续关联应当指的是父类和子类之间的关联,子类继续父类的属性和要领,在JavaScript当中是父组织函数和子组织函数之间的关联。
类自身是对象的笼统情势,类的运用价值末了也是在于经由过程它可以建立对象,
所以子类可以继续父类的属性和要领的意义,就是经由过程子类建立出来的对象可以继续经由过程父类建立出来的对象的属性和要领。
而这类对象之间的继续关联,就是经由过程原型链完成。
在1.2.2节中,我们进修到了经由过程组织函数建立对象的三个主要步骤,个中的一步是把组织函数的prototype对象设置为建立对象的原型。
因而我们将父类的实例对象作为子类的prototype即可以到达继续的目标,以下图所示:
继续的完成
function Person (name, age) {
this.name = name;
this.age = age
}
Person.prototype.sayName = function () {
console.log('my name is ' + this.name);
}
function Student (name, age, school) {
Person.call(this, name, age);
this.school = school;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.saySchool = function () {
console.log('my school is ' + this.school);
}
上面代码完成的继续,遵照了几个准绳:
- 1、由于组织函数建立的对象将公用同一个原型,所以将每一个对象独占的属性写在组织函数中,将对象之间可以公用的要领写在组织函数的prototype中,也就是对象的原型中
- 2、子组织函数继续父组织函数做了两个处所的事情,一是在子组织函数中应用call,挪用父组织函数的要领,二是应用Object.create要领建立一个以父组织函数的prototype为原型的对象。
应用Object.create而不是直接用new 建立一个实例对象的目标是,削减一次挪用父组织函数的实行。
- 3、先经由过程prototype属性指向父组织函数的实例,然后再向prototype增加想要放在原型上的要领。
末了上一张js高等程序设计第三版中的一张源于原型链继续的图
应用class完成继续
下面应用ES6引入的新语法糖,class、extends关键字对上述完成继续的代码举行改写:
class Person {
constructor (name, age) {
this.name = name;
this.age = age;
}
sayName () {
console.log('my name is ' + this.name);
}
}
class Student extends Person {
constructor (name, age, school) {
super(name, age);
this.school = school;
}
saySchool () {
console.log('my school is ' + this.school);
}
}
- class里的constructor 对应本来的组织函数
- class内里的其他要领都是写在本来组织函数的prototype中的
- 子类直接经由过程extends 关键字举行继续
- 子类中可以经由过程super来挪用父类中的要领
本文部分内容来自 https://developer.mozilla.org…
后续
function A() {
}
//函数默许会有一个prototype对象而且具有constructor属性指向他自身
var a = new A()
a instanceof A
function A() {
}
function B() {
}
var proto = {}
B.prototype = proto
A.prototype = proto
var a = new A()
a instanceof B //true
a instanceof Object //true
instanceof 是遍历a 的原型链 寻觅是不是有和 B.prototype 是同一个对象的__proto__ 假如找到就为true