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