首页 > 专栏 > 前端 > 文章详情
反问:JS 的原型链存在的意义是什么?为什么这样设计? 发布于:2023-02-11 09:09:19   来源:Jiannanya   查看:159  讨论:0

先说结论,JavaScript的原型链就是该编程语言为了实现面对对象编程的一种设计,基于原型链,可以让JavaScript对象拥有封装、继承和多态等众多面对对象特性。Akh易塔云建站-模板下载,web开发资源,技术博客

如果你还单身着,或者你曾经单身过,那么你应该对计算机科学界中的面对对象编程有所耳闻。经验尚浅的杀杀觉得谈起找对象的话题来,Java和C#才是老大哥,当然C++也很的class也很经典,但今天它们都不是主角,今天要讲的是JavaScript在面对对象时的原型链设计。Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
0、序言Akh易塔云建站-模板下载,web开发资源,技术博客
 Akh易塔云建站-模板下载,web开发资源,技术博客

要讲雷锋塔,我们还是得先从雷锋开始说起(Java和JavaScript的关系与雷锋和雷锋塔之间的关系差不多)。Akh易塔云建站-模板下载,web开发资源,技术博客

Java的面对对象风格是这样的:Akh易塔云建站-模板下载,web开发资源,技术博客

//HelloWorld.java
public class HelloWorld{
  public static void main(String[] args){
    System.out.println("hello world");
  }
}
C#是这样的:
//HelloWorld.cs Akh易塔云建站-模板下载,web开发资源,技术博客
public class HelloWorld {Akh易塔云建站-模板下载,web开发资源,技术博客
  public static void Main(string[] args) {Akh易塔云建站-模板下载,web开发资源,技术博客
    System.Console.WriteLine(args[0]);Akh易塔云建站-模板下载,web开发资源,技术博客
  }Akh易塔云建站-模板下载,web开发资源,技术博客
}
差不多对吧?然后是C++的:
//HelloWorld.cpp Akh易塔云建站-模板下载,web开发资源,技术博客
#include<iostream>Akh易塔云建站-模板下载,web开发资源,技术博客
using namespace std;Akh易塔云建站-模板下载,web开发资源,技术博客
class Hello {Akh易塔云建站-模板下载,web开发资源,技术博客
  public: Hello() {Akh易塔云建站-模板下载,web开发资源,技术博客
    baicout<<"Hello,";Akh易塔云建站-模板下载,web开发资源,技术博客
  }Akh易塔云建站-模板下载,web开发资源,技术博客
  ~Hello() {Akh易塔云建站-模板下载,web开发资源,技术博客
    cout<<"world"<<endl;Akh易塔云建站-模板下载,web开发资源,技术博客
  }Akh易塔云建站-模板下载,web开发资源,技术博客
};Akh易塔云建站-模板下载,web开发资源,技术博客
int main() {Akh易塔云建站-模板下载,web开发资源,技术博客
  Hello hello;Akh易塔云建站-模板下载,web开发资源,技术博客
  return 0;Akh易塔云建站-模板下载,web开发资源,技术博客
}

是不是觉得C#和Java的容易阅读一点?毕竟人家语言诞生的目的就是纯粹的面对对象编程,而C++只是是在C语言之上在增加了类和对象的特性,为了兼容C风格的代码,就还留着独立的入口main函数。Akh易塔云建站-模板下载,web开发资源,技术博客

最后,JavaScript的对象一般是这样的:Akh易塔云建站-模板下载,web开发资源,技术博客

//HelloWorld.jsAkh易塔云建站-模板下载,web开发资源,技术博客
var Hi = {Akh易塔云建站-模板下载,web开发资源,技术博客
  hi:"HelloWorld",Akh易塔云建站-模板下载,web开发资源,技术博客
  bye:"GoodByeWorld"Akh易塔云建站-模板下载,web开发资源,技术博客
};

我的天呐,这是一个对象?Akh易塔云建站-模板下载,web开发资源,技术博客

对,看起来它好像一个python的字典对吧,但在雷锋塔中,它确实是一个叫做“对象”的妖怪。Akh易塔云建站-模板下载,web开发资源,技术博客

在传统写法中,JavaScript生成实例对象的方法是通过构造函数:Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
也可以是这样:Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
但它还是长着妖怪的模样,所以ES6引入了class关键字这个语法糖:Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
 Akh易塔云建站-模板下载,web开发资源,技术博客

虽然看起来舒服多了,但它实际上只是相当于涂了点胭脂,好看了一些,“妖怪”的本质还是没有变化。那这个本质是什么呢?就是原型链。Akh易塔云建站-模板下载,web开发资源,技术博客

所以,到底什么是JavaScript的原型链?Akh易塔云建站-模板下载,web开发资源,技术博客

JavaScript的原型链就是该编程语言为了实现面对对象编程的一种设计,基于原型链,可以让JavaScript对象拥有封装、继承和多态等面对对象特性。Akh易塔云建站-模板下载,web开发资源,技术博客

如果你是从Java或者C++开始学习编程的,那一定会对此感到混乱。所以接下来,就讲一下原型链是什么。Akh易塔云建站-模板下载,web开发资源,技术博客

1、prototypeAkh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
在JavaScript中,每个函数都有一个prototype属性,这个属性指向函数的原型对象。Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
 Akh易塔云建站-模板下载,web开发资源,技术博客

上述例子中,函数的prototype指向了一个对象,而这个对象正是调用构造函数时创建的实例的原型,也就是person1和person2的原型。Akh易塔云建站-模板下载,web开发资源,技术博客

原型的概念:每一个javascript对象(除null外)创建的时候,就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型中“继承”属性。Akh易塔云建站-模板下载,web开发资源,技术博客

让我们用一张图表示构造函数和实例原型之间的关系:Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
2、__proto__Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
这是每个对象(除null外)都会有的属性,叫做__proto__,这个属性会指向该对象的原型。Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
同样是用一张图表示:Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
3、constructorAkh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
每个原型都有一个constructor属性,指向该关联的构造函数。Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
所以再更新下关系图:Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
4、实例与原型Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
 Akh易塔云建站-模板下载,web开发资源,技术博客

在这个例子中,我们给实例对象 person 添加了 name 属性,当我们打印 person.name 的时候,结果自然为 Daisy。Akh易塔云建站-模板下载,web开发资源,技术博客

但是当我们删除了 person 的 name 属性时,读取 person.name,从 person 对象中找不到 name 属性就会从 person 的原型也就是 person.__proto__ ,也就是 Person.prototype中查找,幸运的是我们找到了 name 属性,结果为 Kevin。Akh易塔云建站-模板下载,web开发资源,技术博客

但是万一还没有找到呢?原型的原型又是什么呢?Akh易塔云建站-模板下载,web开发资源,技术博客
 Akh易塔云建站-模板下载,web开发资源,技术博客

5、原型的原型Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
在前面,我们已经讲了原型也是一个对象,既然是对象,我们就可以用最原始的方式创建它,那就是:Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
其实原型对象就是通过 Object 构造函数生成的,结合之前所讲,实例的 __proto__ 指向构造函数的 prototype ,所以我们再更新下关系图:Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
6、原型链Akh易塔云建站-模板下载,web开发资源,技术博客
 Akh易塔云建站-模板下载,web开发资源,技术博客

简单的回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。——摘自《javascript高级程序设计》Akh易塔云建站-模板下载,web开发资源,技术博客

其实简单来说,就是上述4-5的过程。Akh易塔云建站-模板下载,web开发资源,技术博客

继上述五中所说,那 Object.prototype 的原型呢?Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
 Akh易塔云建站-模板下载,web开发资源,技术博客

null 表示“没有对象”,即该处不应该有值。Akh易塔云建站-模板下载,web开发资源,技术博客

所以 Object.prototype.__proto__ 的值为 null 跟 Object.prototype 没有原型,其实表达了一个意思。Akh易塔云建站-模板下载,web开发资源,技术博客

所以查找属性的时候查到 Object.prototype 就可以停止查找了。Akh易塔云建站-模板下载,web开发资源,技术博客

最后一张关系图也可以更新为:Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线。Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
7、一张图秒懂 JavaScript 原型链Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
Akh易塔云建站-模板下载,web开发资源,技术博客
8、结尾Akh易塔云建站-模板下载,web开发资源,技术博客
 Akh易塔云建站-模板下载,web开发资源,技术博客

相信上述1-7可以让你对JavaScript的原型链有所了解,但原型链存在的意义是什么呢?Akh易塔云建站-模板下载,web开发资源,技术博客

让我们回到开头,再联系一下序幕中Java、C#、C++的面对对象原理,容易知道,JavaScript的原型链就是该编程语言为了实现面对对象编程的一种设计,基于原型链,可以让JavaScript对象拥有封装、继承和多态等众多面对对象特性。Akh易塔云建站-模板下载,web开发资源,技术博客

就好像,继承关系在这里,变成了一条链表一样的数据结构,冥冥之中,影响着众多web开发者。Akh易塔云建站-模板下载,web开发资源,技术博客

评论

  • 匿名