简述原型链

产品倒闭
• 阅读 933

简述原型链

背景
JavaScript 是动态的,本身不提供一个 class 的实现。即便是在 ES2015/ES6 中引入了 class 关键字,但那也只是语法糖,JavaScript 仍然是基于原型的

当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象(object)都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(__proto__),层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。

几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。

链接:https://developer.mozilla.org...

先说几个名词概念

  1. prototype 显式原型
  2. proto 隐式原型

介绍下 引用类型

  1. 都具有对象特性,即可自由扩展属性。
  2. 都有一个隐式原型 proto 属性,属性值是一个普通的对象。
  3. 隐式原型 __proto__ 的属性值指向它构造函数的显式原型 prototype 的属性值。
  4. 当获取一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的隐式原型 __proto__(也就是它的构造函数的显式原型 prototype)中寻找。

看个 🌰

function Student(name) {
    this.name = name
}
const stu = new Student('xiaomin')
stu.name  // 'xiaomin'
// toString 为对象常用方法,返回一个表示该对象的字符串
stu.toString()  // '[object Object]'

// 给 toString 赋值
stu.prototype.toString = function stuToString() {
  return `${this.name}`;
};
console.log(stu.toString());
// expected output: "Gabby"

问题抛出:为什么 stu 一开始没有定义 toString 却能获取到呢?

stu 实例先从自身出发查找,发现没有 toString 方法。找不到,就往上走,找 Student 构造函数的 prototype 属性,还是没找到。由于构造函数的 prototype 是一个对象,那对象的构造函数是 Object ,所以就找到了 Object.prototype 下的 toString 方法。

这里补充说明下,如果最终都未找到,则返回 undefined。并且此时 Object.prototype 的隐式原型指向 null
tips: null 是为了避免死循环而设置的

stu.xx // undefined

简述原型链
引申一个概念:instanceof
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);
console.log(auto instanceof Car);
// expected output: true
console.log(auto instanceof Object);
// expected output: true

instabceof 实现方式(原理)

// 变量R的原型 存在于 变量L的原型链上
function instance_of (L, R) {    
  // 验证如果为基本数据类型,就直接返回 false
  const baseType = ['string', 'number', 'boolean', 'undefined', 'symbol']
  if(baseType.includes(typeof(L))) { return false }

  let RP = R.prototype;  // 取 R 的显示原型
  L = L.__proto__; // 取 L 的隐式原型
  while (true) {
    if (L === null) { // 找到最顶层
      return false;
    }
    if (L === RP) { // 严格相等
      return true;
    }
    L = L.__proto__;  // 没找到继续向上一层原型链查找
  }
}

instanceof 判断流程如下:

  1. f 的隐式原型 __proto__ 和 Foo.prototype, 是相等的所以返回 true 。
  2. f 的隐式原型 __proto__ ,和 Object.prototype 不等, 所以继续往上走。f 的隐式原型 __proto__ 指向 Foo.prototype ,所以继续用 Foo.prototype.__proto__ 去对比 Object.prototype, 判断相等返回 true。(因为 Foo.prototype 就是一个普通的对象)

参考链接:https://juejin.cn/post/693449...

丰富一下知识

基于原型链的继承

1.继承属性
JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾
给对象设置属性会创建自有属性。获取和设置行为规则的唯一例外是当继承的属性带有 getter 或 setter 时(没能理解)。

2.继承方法
在 JavaScript 里,任何函数都可以添加到对象上作为对象的属性。函数的继承与其他的属性继承没有差别
当继承的函数被调用时,this 指向的是当前继承的对象,而不是继承的函数所在的原型对象
🌰

var o = {
  a: 2,
  m: function(){
    return this.a + 1;
  }
};

console.log(o.m()); // 3
// 当调用 o.m 时,'this' 指向了 o.

var p = Object.create(o);
// p是一个继承自 o 的对象

p.a = 4; // 创建 p 的自身属性 'a'
console.log(p.m()); // 5
// 调用 p.m 时,'this' 指向了 p
// 又因为 p 继承了 o 的 m 函数
// 所以,此时的 'this.a' 即 p.a,就是 p 的自身属性 'a' 
点赞
收藏
评论区
推荐文章
晴空闲云 晴空闲云
3年前
JavaScript中isPrototypeOf函数详解
有时看一些框架源码的时候,会碰到isPrototypeOf()这个函数,那么这个函数有什么作用呢?isPrototypeOf()isPrototypeOf()是Object函数(类)的下的一个方法,用于判断当前对象是否为另外一个对象的原型,如果是就返回true,否则就返回false。这个函数理解的关键是在原型链上,这个据说是JavaScript
Stella981 Stella981
3年前
JavaScript prototype原型用法
JavaScript对象原型所有JavaScript对象都从原型继承属性和方法。<!DOCTYPEhtml<html<metacharset"utf8"<titlejs</title<body<h2JavaScript对象</h2
Stella981 Stella981
3年前
JavaScript学习总结(十七)——Javascript原型链的原理
一、JavaScript原型链ECMAScript中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。在JavaScript中,用__proto__属性来表示一个对象的原型链。当查找一个对象的属性时,JavaScript会向上遍历原型
Stella981 Stella981
3年前
ES6 系列之 Babel 是如何编译 Class 的(上)
_摘要:_ 前言在了解Babel是如何编译class前,我们先看看ES6的class和ES5的构造函数是如何对应的。毕竟,ES6的class可以看作一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。constructorES6中:\
Stella981 Stella981
3年前
ES6中的super
对象方法中的super原型对于javascript来说非常重要,甚至可以说是javascript中最为重要的知识点。然而,很多人一看到原型就懵逼。ES5我们可以使用Object.getPrototypeOf()来返回原型对象,使用Object.setPrototypeOf()来设置原型对象。看下面的例子:letpe
Wesley13 Wesley13
3年前
JS原型、原型链深入理解
原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有”prototype”属性,函数对象有”prototype”属性,原型对象有”constructor”属性。原型是JavaScript中一个比较难理解的概念,原型相关的属性也比较多,对象有”prototype”属性,函数对象有”prototype”属性,原型对
Stella981 Stella981
3年前
JavaScript 原型和原型链的定义和使用
目录JavaScript原型和原型链的定义和使用01原型原型定义原型实例理解书写方法1:属性单个定义书写方法2:属性多个定义02原型链原型链定义原型链实例理解最终原型问题03原型和原型链的使用应用举例Ja
Stella981 Stella981
3年前
JavaScript 基于原型链的继承
JavaScript对象是动态的属性“包”(指其自己的属性)。JavaScript对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。遵循ECMAScript标准,someObject.Prototype
Stella981 Stella981
3年前
Javascript中,实现类与继承的方法和优缺点分析
Javascript是一种弱类型语言,不存在类的概念,但在js中可以模仿类似于JAVA中的类,实现类与继承第一种方法:利用Javascript中的原型链1//首先定义一个父类23functionAnimal(name,age){4//定义父类的属性5thi
Stella981 Stella981
3年前
Javascript 构造函数和类
1.构造函数构造函数的名称一般都是首字母大写挂载在this上面的属性为实例属性,实例属性再每个实例间都是独立的原型链属性通过prototype添加,他是所有实例共享的类方法/静态属性只能由构造函数本身访问当实例属性和原型链上的属性重名时,优先访问实例属性,没有实例属性再访问原型属性大多数浏览器的ES5实现之中,每一个对象都有\_\_pr
Stella981 Stella981
3年前
JavaScript基础之原型对象和原型链
!(https://oscimg.oschina.net/oscnet/64fbb850bccf434ebbf033f599907fb3.png)原型对象!(https://oscimg.oschina.net/oscnet/9994724f3f4d47db8b0e07b93c3250e7.jpg)原型对象简单来说就是