原型(prototype
)
函数的 prototype
属性(图)
- 每个函数都有一个
prototype
属性,它默认指向一个Object
空对象(即称为:原型对象) - 原型对象中有一个属性
constructor
,它指向函数对象
给原型对象添加属性(一般都是添加方法)
- 作用:函数的所有实例对象自动拥有原型中的属性(方法)
显式原型与隐式原型
- 每个函数
function
都有一个prototype
属性,即 显式原型 - 每个实例对象都有一个
__proto__
,可称为隐式原型 - 实例对象的隐式原型的值
===
其对应构造函数的显示原型的值 - 内存结构(图)
-
总结:
- 函数的
prototype
属性:在定义函数时自动添加的,默认值是一个空的Object
对象 - 对象的
__proto__
属性:创建对象时自动添加的,默认值为构造函数的prototype
属性值 - 程序员能直接操作显示原型,但不能直接操作隐式原型(
ES6
之前)
- 函数的
原型链
原型链(图解)
-
访问一个对象的属性时,
- 先在自身属性中查找,找到返回
- 如果自身属性中没有,再沿着
__proto__
这条链向上查找,找到返回 - 如果最终没有找到,返回
undefined
- 原型链的别名:隐式原型连
- 原型链的作用:查找对象的属性(方法)
构造函数/原型/实例对象的关系(图解)
var o1 = new Object()
var o2 = {}
构造函数/原型/实例对象的关系2(图解)
下面这个图需要仔细理解。
原型继承
- 构造函数的实例对象自动拥有构造函数原型对象的属性(方法)
- 利用的就是原型链
原型链——属性问题
- 读取对象的属性值时:会自动到原型链中查找
- 设置对象的属性值时:不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
- 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上。
探索 instanceof
instanceof
是如何判断的?
- 表达式:
A instanceof B
- 如果
B
函数的显式原型对象在A
对象的(隐式)原型链上,返回true
,否则返回false
Function
是通过new
自己产生的实例
案例1
function Foo() { } var f1 = new Foo(); console.log(f1 instanceof Foo); // true console.log(f1 instanceof Object); // true
案例2(重要)
console.log(Object instanceof Function); // true console.log(Object instanceof Object); // true console.log(Function instanceof Function); // true console.log(Function instanceof Object); // true function Foo() {} console.log(Object instanceof Foo); // false
注意:Function
的显示原型和隐式原型是一样的。
面试题
测试题1
var A = function() { } A.prototype.n = 1 var b = new A() A.prototype = { n: 2, m: 3 } var c = new A() console.log(b.n, b.m, c.n, c.m) // 1 undefined 2 3
测试题2
var F = function(){}; Object.prototype.a = function(){ console.log('a()') }; Function.prototype.b = function(){ console.log('b()') }; var f = new F(); f.a() // a() f.b() // 报错 f.b is not a function F.a() // a() F.b() // b()
对照下图理解: