前言
前些日子,在掘金上看到一片热门文章。该文作者以面试官的角度,详细阐述了作为一名 web 应聘者应该具有哪些技能,才会更让人青睐。
在对比自身的过程中,发现有一些问题,或许了解,但不全面,这也是本系列文章诞生的缘由。
什么是原型与原型链
JavaScript 常被描述为一种基于原型的语言 (prototype-based language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法(源自 MDN)
给大家讲个恐怖故事帮助理解:
"有一个伟大的科学家,
找到一个恐龙的化石,
克隆了一只小母鸡,
小母鸡拥有了吃人的能力,
科学家被吃了..."
在这个恐怖故事中,小母鸡是实例,恐龙化石的原型就是小母鸡原型链的第一层。
再给大家讲个幽默故事深化理解:
"有一个伟大的科学家,
找到一个恐龙的化石,
克隆了一只小母鸡,
没想到恐龙化石生前竟然是哈士奇,
小母鸡成为了科学家的二哈... "
在这个幽默故事中,小母鸡是实例,恐龙化石的原型就是小母鸡原型链的第一层,恐龙和哈士奇的原型合起来是它的原型链 (/ □ )
原型链和继承的关系
大家都知道面向对象的三大浪漫是继承、封装和多态。
JavaScript 虽然不能通过类来实现的面向对象,但通过原型链一样轻松实现继承。
继承属性
/* * 创建一个构造函数,初始化时,对 this (this 指向实例对象) 赋值 */function func1(){ this.a = 1 this.b = 2}/* * 给构造函数的原型定义属性 */func1.prototype.b = 3func1.prototype.c = 4// 我们看看实例对象现在拥有了什么?var f1 = new func1()// a 是 f1 的自身属性,因此打印1console.log(f1.a) => 1// b 是 f1 的自身属性,因此打印2// b 同时也是 f1 原型属性,它的值为3,但是不会被打印。官方解释是因为属性遮蔽 (property shadowing),3不会被访问到。// 说人话就是,当从原型链查找属性时,优先找到了自身属性的 b ,因此原型属性的 b 不会再去找了。console.log(f1.b) => 2// c 不是 f1 的自身属性// 继续找 f1 的原型,f1 的原型上有 c,因此打印3console.log(f1.c) => 4// 开始愚公移山...// d 不是 f1 的自身属性// 继续找 f1 的原型,f1 的原型上也没有 c// 继续找 f1 的原型的原型,f1 的原型的原型是 object , object 也没有 d// 继续找 object 的原型,object 的原型是 null,停止搜索// 停止搜索,打印 undefinedconsole.log(f1.d) => undefined复制代码
继承方法
继承方法与继承属性没有区别
function func1(){ this.a = 1 this.b = 2 this.func = function(){ console.log('hello world') }}// f1 拥有了 func1 的 func 方法var f1 = new func1()f1.func() => hello world复制代码