前言
工欲善其事,必先利其器。 大家好,我是龙哈哈。一个
Java,JavaScript两栖动物。
本篇是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是多种语言风格的混合产物,既包含了函数式编程又有面向对象编程,从诞生的那天起,就自带
争议属性Netscape和Brendan Eich可能也没有想到,JavaScript将来会成为全球最流行的编程语言。
对JavaScript Coder来说,奇妙的旅程,就此开始。
什么是原型编程
原型编程 是 面向对象编程 的一种风格和方式。
在原型编程中,行为重用(在基于类的语言通常称为
继承)是通过复制已经存在的原型对象的过程实现的。这个模型一般被认为是无类的、面向原型、或者是基于实例的编程。 简单来说,这种风格是在不定义class的情况下创建一个object。
Self语言是原型编程这一派的祖师爷, JavaScipt在设计的时候采用了这种编程方式。
JavaScipt原型的三座大山
- prototype
- __ proto __
- constructor 首先要明确
prototype是Function独有__ proto __,constructor是Object独有
经典祭祖图
一脸懵逼的进来,一脸懵逼的出去 不慌,我们先看一段代码
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
总结
JavaScript借鉴Self,使用基于原型(prototype)的继承机制Object特有__proto__和constructor,Function特有prototypeprototype也是个Object,也有__proto__和constructorObject的__proto__指向创建该对象的函数的prototype- 对象之间通过
__proto__连接起来,当前对象上不存在的属性方法可以通过__proto__一层层往上查找,直到终点站null,通过__proto__将不同对象连接起来的链路就是原型链 constructor指向对象的构造函数,所有函数(也可看做是对象)最终的构造函数都指向Function
最后
三人行,必有我师焉
掘金不停,代码不止
互相学习,共同进步 文中如有错误,欢迎在评论区指正。
如果这篇文章对你有所帮助,欢迎点赞、评论和关注。
系列文章
- 【Magic JavaScript】数据类型,你真的掌握了吗?
- 【Magic JavaScript】原型编程,你真的理解了吗?
- 【Magic JavaScript】函数编程,你真的熟练了吗?
- 【Magic JavaScript】异步编程,你真的学会了吗?
- 【Magic JavaScript】事件循环,你真的明白了吗?
- 【Magic JavaScript】垃圾回收,你真的清楚了吗?