【Magic JavaScript】原型编程,你真的理解了吗?

1,193 阅读4分钟

前言

工欲善其事,必先利其器。 大家好,我是龙哈哈。一个 JavaJavaScript 两栖动物。
本篇是 FuckingJavaScript 系列的第二篇,我们来一起回顾一下 原型 的相关知识。

什么是原型编程

为什么其他的 面向对象 语言没有 原型JavaScript 却要有呢?
带着这个疑问,我们去查阅下JavaScript发展史的相关资料

JavaScript诞生史

爸爸是初代浏览器王朝的王者 网景(Netscape)
没错,就是window.navigator.appName的那个Netscape
Netscape 招募来了Scheme专家 Brendan Eich,想把 Scheme 嵌入进浏览器中
这也就解释了JavaScript中函数是第一公民的原因。 在Javascript出生之前,Netscape浏览器支持Java程序运行,所以设计的初衷就是要设计出一个与Java相似,但是比Java简单的语言。
这就是命名 Java+Script 的由来,祖上还是和Java有一定渊源的

设计时间

开始结束,只用了天。

设计思路

  • 借鉴C的基本语法
  • 借鉴Java的数据类型和内存管理
  • 借鉴Scheme,将函数提升到第一等公民的地位
  • 借鉴Self,使用基于原型(prototype)的继承机制

JavaScript是多种语言风格的混合产物,既包含了函数式编程又有面向对象编程,从诞生的那天起,就自带争议属性 NetscapeBrendan Eich 可能也没有想到,JavaScript将来会成为全球最流行的编程语言。
JavaScript Coder 来说,奇妙的旅程,就此开始。

什么是原型编程

原型编程面向对象编程 的一种风格和方式。

在原型编程中,行为重用(在基于类的语言通常称为继承)是通过复制已经存在的原型对象的过程实现的。这个模型一般被认为是无类的、面向原型、或者是基于实例的编程。 简单来说,这种风格是在不定义class的情况下创建一个 object

Self语言是原型编程这一派的祖师爷, JavaScipt在设计的时候采用了这种编程方式。

JavaScipt原型的三座大山

  • prototype
  • __ proto __
  • constructor 首先要明确
  1. prototypeFunction 独有
  2. __ proto __, constructorObject 独有

经典祭祖图

image.png

一脸懵逼的进来,一脸懵逼的出去 不慌,我们先看一段代码

function Hero(name) {
    this.name = name;
}
// Hero 的 prototype
Hero.prototyoe.country = 'demacia';
// 创建实例
var garen = new Hero('garen');
var jarvanIV = new Hero('jarvanIV');
// 实例可继承函数原型对象的属性
console.log(garen.country); // demacia
console.log(jarvanIV.country); // demacia
// 函数的原型对象
console.log(Hero.prototype);
// 对象的原型
console.log(garen.__proto__);
console.log(jarvanIV.__proto__);

prototype

函数的原型对象,Function 独有,指向了一个对象,对象是 调用该函数而创建的实例的原型__proto__

prototype 本身也是个 Object,所以 prototype也有 __proto__constructor

这里可能会有同学疑惑,我们带着疑问接着往下看

__ proto __

对象的原型,Object 独有,指向了一个对象,对象是 创建该对象的函数的原型对象

// 对象的原型 和 函数的原型对象,指向同一地址,是相同的对象
console.log(garen.__proto__ === Hero.prototype);

我们上面说 prototype也是对象,所以也有 __proto__,所以延伸一下就有

// Hero.prototype是个对象
// 对象的原型就指向创造ta的函数的原型对象,即 Object 的 原型对象
console.log(Hero.prototype.__proto__ === Object.prototype); // true
// 终点站到了 null
console.log(Object.prototype.__proto__ === null); // true

对象之间通过__proto__连接起来,这就是原型链。当前对象上不存在的属性方法可以通过__proto__一层层往上查找,直到终点站 null

我们常用的不同数据类型的方法都是靠 __proto__ 继承而来

constructor

构造函数,Object 独有,顾名思义,指向了函数本身

// 函数的原型对象的构造函数,指向函数本身
console.log(Hero.prototype.constructor === Hero); // true

函数本身也是个对象,所以也有 __proto__,所以延伸一下就有

// 命名函数的 原型 指向 Function 的原型对象
console.log(Hero.__proto__ === Function.prototype); // true
// Function原型对象的原型,指向 Object 的原型对象
console.log(Function.prototype.__proto__ === Object.prototype); // true
// 终点站到了 null
console.log(Object.prototype.__proto__ === null); // true

总结

  1. JavaScript 借鉴 Self,使用基于原型(prototype)的继承机制
  2. Object特有 __proto__constructorFunction 特有 prototype
  3. prototype 也是个Object,也有 __proto__constructor
  4. Object__proto__ 指向 创建该对象的函数prototype
  5. 对象之间通过__proto__连接起来,当前对象上不存在的属性方法可以通过__proto__一层层往上查找,直到终点站 null,通过 __proto__ 将不同对象连接起来的链路就是原型链
  6. constructor 指向对象的构造函数,所有函数(也可看做是对象)最终的构造函数都指向Function

最后

三人行,必有我师焉
掘金不停,代码不止
互相学习,共同进步 文中如有错误,欢迎在评论区指正。
如果这篇文章对你有所帮助,欢迎点赞、评论和关注。

系列文章