【FuckingJavaScript系列】原型编程,你真的理解了吗?

前言

工欲善其事,必先利其器。

大家好,我是龙哈哈。一个 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

最后

三人行,必有我师焉
掘金不停,代码不止
互相学习,共同进步

文中如有错误,欢迎在评论区指正。
如果这篇文章对你有所帮助,欢迎点赞、评论和关注。

系列文章

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享