JS & 原型、原型链,继承,类之间的关系

一、什么是原型?

原型(prototype) 是一个对象 ,为什么 JS 中的基本类型能调用一些方法?
就是因为它们继承了爸爸们在原型中定义的属性或方法;比如一个简单的字符串为什么会有 .length 属性呢?

const str = 'Hello,world'
console.log(str.length)

原因是 String.prototype.length 就有这个属性, String 这个原始对象就是 str 的爸爸。
现在我们明白了,原型(prototype)原来就是定义一些给孩子们用的工具。

二、什么是原型链?

问题来了,上面的 str 字符串是如何继承 String 爸爸的 prototype 对象呢?换句话说,是如何找到爸爸的工具?
答案是 __proto__ 俗称原型链,它指向着上一层 prototype 原型对象(这里是 String.prototype),看例子:

const str = 'Hello,world'
console.log(str.__proto__ === String.prototype) // 打印:true

故事开始变得有趣了,如果把 __proto__ 切断换成别的,是不是 length 属性就消失了呢?,看例子:

const str = 'Hello,world'
str.__proto__ = ''
console.log(str.length) // 打印:11

已经将 __prot__ 变成空字符串了,咋还能调用 length 方法,剧情不按套路来?
相信眼睛细锐的伙伴应该猜到了,空字符串 '' 本身自带 __proto__ 属性呀!所以关系链还存在呢。

有没有办法,能让赋值的东西 不包含 __proto__ 这玩意呢?试试 null

const str = 'Hello,wolrd'
str.__proto__ = null
console.log(str.length) // 打印:11

结果还是 11,好家伙这就有点奇怪了,莫非 __proto__ 不能强行更改?
其实答案部分正确,对于基本类型,无论怎么赋值,str.__proto__ 始终指向 String.prototype
于是得出一个结论:基本类型的原型链不能切断

然而对于引用类型,剧情就会按照套路来,我们来验证下:

const obj = {}
obj.toString() // 打印:'[object Object]'
obj.__proto__ = null;
obj.toString() // 报错:toString 不是一个 Function 。

于是又得出一个结论:引用类型的原型链可以切断

三、自定义函数可享受原型

基本类型和引用类型都能继承爸爸们的工具,这个 feature 非常高效啊,JS 作者为了让开发人员也能享受这种待遇,于是给自定义函数也加上了 原型 prototype 的功能,前提条件是得使用 new 关键字实例化函数时,这些实例化函数便能享受函数(俗称“构造函数”)自定义的 prototype 工具,来看看代码:

function Animal() {}
Animal.prototype.run = () => console.log('Run run run!')
Animal.prototype.eat = () => console.log('Eat eat eat!')

const dog = new Animal()
dog.run() // 打印:Run run run
console.log(dog.__proto__ === Animal.prototype) // 打印:true
const cat = new Animal()
console.log(cat.__proto__ === Animal.prototype) // 打印:true
cat.run() // 打印:Run run run

Tip: 既然 dog 和 cat 都能享有 run 和 eat 方法,这像什么关系?没错,像继承关系。于是,JS 中的继承概念就这么出来了。

四、什么是类?

既然 JS 能模拟 继承,那制造一个类 Class 出来也没问题吧?于是,基于原型(prototype)和原型链(__proto__) 这俩家伙的组合,便有了现在的类,咋们来看例子:

class Animal{
	constructor() {}
	run() { console.log('Run run run') }
	eat() { console.log('Run run run') }
}
const dog = new Animal()
dog.run() // 打印:Run run run

console.log(dog.__proto__ === Animal.prototype) // 打印:true

看看,类这家伙就是一个语法糖,对不对?

完!

你可能感兴趣的:(JavaScript,javascript)