美文网首页
JavaScript原型链

JavaScript原型链

作者: lobster1991 | 来源:发表于2019-03-25 11:52 被阅读0次

除了6种原始数据类型,JavaScript中的其他数据皆为对象。JavaScript的继承是由原型链(prototype chain)来实现的。

​每一个JavaScript对象都有一个私有对象指向另外一个对象,也就是原型(prototype)。根据ES6的规定,我们可以用 someObject.[[Prototype]] 来表示 someObject 对象的原型。 [[Prototype]] 对象可以通过 Object.getPrototypeOf() 方法和Object.setPrototypeOf() 方法来获取和设定新对象。我们也经常用 someObject.__proto__ 方式来操作原型,该方法不是JavaScript的标准,也不被官方推荐使用,不过大部分浏览器都是支持的。

我们通过__proto__属性来获取对象的原型对象,原型对象又可以通过__proto__属性来获取它的原型对象,这样,我们通过不断调用__proto__属性,就可以获取的层层的原型对象,这也就是我们所说的原型链。几乎所有的对象,其原型链末端都指向Object.prototype

var arr = [];
arr.__proto__ === Array.prototype;
arr.__proto__.__proto__ === Object.prototype
arr.__proto__.__proto__.__proto__ === null

​我们创建一个对象的过程是怎样的呢,下面举例说明

function Human(name, age) {
    this.name = name || '';
    this.age = age || 0;
}
var p = new Human('zhang san', 20);
p.name // 'zhang san'
p.age // 20

这里,我们通过构造函数创建了一个新的对象p,那这个对象创建的具体过程是怎样的呢,仅以上述代码为例,具体的创建过程如下:

  1. 创建一个空对象
  2. 将新对象的原型绑定到Human的prototype属性上
  3. 调用构造函数Human,并将this绑定到新对象上
  4. 判断返回值,如果返回值不是一个Object对象,就返回第一步中创建的对象,否则返回该Object对象,第一步中创建的对象也将被弃用。当然一般我们不会在构造函数中返回其他对象。

用代码表示就是:

var obj = new Object();
obj.__proto__ = Human.prototype;
Human.call(obj, 'zhang san', 20);
var p = Human() instanceof Object ? Human() : obj;

这里需要注意的是,构造函数的prototype属性和对象的__proto__属性不是一个概念。除了Object,每个对象都有一个__proto__属性;每个函数都有一个prototype属性,函数也是对象,因此也有__proto__属性。

函数的prototype属性包含两个属性:

  1. constructor属性指向函数对象自身;
  2. __proto__属性代表该函数对象的原型

​ 构造函数其实就是普通函数,只不过构造函数的用途是创建对象。我们知道,JavaScript中除了6个基本数据类型,其他都是对象,函数也不例外,函数就是可被调用的对象。

​ 对象的原型也是一个对象,根据上面的分析我们可以发现,当我们创建一个新的对象时,对象的__proto__属性指向了特定的原型对象,不管我们通过Human函数创建多少个对象,其原型都是同一对象,即Human.prototype

let p1 = new Human;
let p2 = new Human;
p1.__proto__ === p2.__proto__; // logs: true
// 改变原型对象时,所有继承自该原型的对象都将收到影响
Human.prototype.a = 1;
p1.a === 1; // logs: true
p2.a === 1 // logs: true

​ 当我们想要获取对象某个属性的值时,JavaScript会执行以下操作:

  1. 首先会去查询该对象自身的属性,查找到了就返回值
  2. 如果对象自身不存在该属性,就去原型链中查找,如果原型链中有这个属性,就返回这个属性的值。
  3. 如果原型链中也没有这个属性,JavaScript就会认为不存在该属性。

如果对象和原型链中都有同一个属性,那我们默认查到的会是对象自身的属性。

let person = new Human;
Human.prototype.country = 'China';
console.log(person.country); // logs: China
person.country = 'United States'; // 这一步创建了对象自己的属性
console.log(person.country); // logs: United States
console.log(person.__proto__.country) // logs: China

现在我们知道对象跟构造函数的关系了,那如果我们创建对象后,又改变了构造函数自身的属性,会对已生成的对象产生影响吗?一般而言,没大影响。从对象的创建过程我们可以看出,只有绑定到this的属性会在对象创建的过程中起作用,其他对象不会对对象的创建产生影响。但我们也知道对象的__proto__属性其实就是函数的prototype属性,而prototype属性中的constructor属性就指向函数本身,因此我们依然可以以一种曲径通幽的方式访问到函数自身的属性。

let libai = new Human('libai', 1318);
console.log(libai); // logs: HUman {name: 'libai', age: 1318}
Human.address = 'shandong';
console.log(libai.address); // logs: undefined
console.log(libai.__proto__.constructor.address) // logs: shandong

通过构造函数创建的对象,继承的属性只是函数prototype属性指向的对象的属性,当我们想要修改对象原型的属性,我们只能在修改prototype对象上的属性。

let libai = new Human('libai', 1318);
Human.prototype.address = 'china';
console.log(libai.address); // logs: china

除了通过构造函数创建对象,我们还可以通过Object.create()方法创建对象。通过Object.create()方法,我们可以不用再通过创建构造函数来创建对象,而是直接通过对象来创建对象。

let female = new Human('female');
let f = Object.create(female);
f.__proto__ === female; // logs: true

这里我们不难看出,对象f的原型对象就是female,而不是构造函数的prototype属性。对象f的原型链如下:

f.__proto__ === female;
f.__proto__.__proto__ === Human.prototype;
f.__proto__.__proto__.__proto__ === Object.prototype;
f.__proto__.__proto__.__proto__.__proto__ === null;

相关文章

  • 【javascript】继承

    javascript只支持实现继承,而且继承主要是依靠原型链来实现的。 原型链 javascript将原型链作为实...

  • js原型、原型链、继承的理解

    一、原型、原型链 原型是Javascript中的继承的基础,JavaScript的继承主要依靠原型链来实现的。 原...

  • javaScript原型链

    javaScript原型链概念JavaScript之继承(原型链)数据结构var Person = functio...

  • 原型、原型链

    (什么是原型、原型链?有什么作用) JavaScirpt深入之从原型到原型链 图解 Javascript 原型链 ...

  • JavaScript 原型、原型链与原型继承

    原型,原型链与原型继承 用自己的方式理解原型,原型链和原型继承 javascript——原型与原型链 JavaSc...

  • javascript碎片知识001

    javascript中的对象(原型,原型链) 什么是原型? 原型是JavaScript中的继承的基础,JavaSc...

  • 面试题 Javascript

    介绍JavaScript的基本数据类型。 说说写JavaScript的基本规范? JavaScript原型,原型链...

  • JavaScript 基础知识点

    介绍JavaScript的基本数据类型。 说说写JavaScript的基本规范? JavaScript原型,原型链...

  • 原型和原型链篇

    原型和原型链 1.理解原型设计模式以及JavaScript中的原型规则 原型设计模式JavaScript是一种基于...

  • 原型链 完整版(JavaScript)

    原型链 完整版(JavaScript)

网友评论

      本文标题:JavaScript原型链

      本文链接:https://www.haomeiwen.com/subject/idlvvqtx.html