附上别人总结的例子,方便查阅:JS原型链简单图解
个人笔记:记住下面的图。
实例对象的隐式指向(__proto__)的原型等于构造器的显式指向的(prototype)原型。
比如:
function Foo(){}
var f1 = new Foo();
console.log(f1.__proto__ === Foo.prototype); // true
由图中可以得出一下结论
Object.__proto__.__proto__ === Object.prototype // true
Object.__proto__ === Function.prototype // true
之后所有的讲解围绕这幅图展开。(图中__proto__代表隐式指向,prototype代表显式指向)
原型链示意图1
Object.__proto__即为Function.prototype,控制台显示为
为什么呢?Object也是一个函数,比如函数function Foo(){}可以看成var Foo = new Function();
实例对象的隐式指向(__proto__)的原型等于构造器的显式指向的(prototype)原型,那么Object.__proto__就是等于Function.prototype。所以js说万物皆对象不是没有道理的。
总结:一般看到控制台这样的[native code],马上想到Function的显式指向的原型对象,再结合原型链示意图1思考。
Object.__proto__.__proto__即为Object.prototype,控制台显示如下:
为什么Object.__proto__.__proto__即为Object.prototype呢?由上一个问题已经得出Object.__proto__即为Function.prototype(Function显式指向的原型对象,是一个对象),由实例对象的隐式指向(__proto__)的原型等于构造器的显式指向的(prototype)原型,得出Function.prototype.__proto__(实例对象的隐式指向的原型)等于Object.prototype(构造器的显式指向的原型),所以Object.__proto__.__proto__等于Object.prototype。
A instanceof B
只要A的隐式原型链(__proto__)能够追溯到B的显式指向的原型对象(prototype),就返回true,否则为false。
function fn(){}
var obj = {}
console.log(fn instanceof Function)//true
/*
把function fn(){}看成var fn = new Function();
那么fn.__proto__就是Function.prototype,fn的隐式原型链能到达Function的显式指向的原型对象,为true
*/
console.log(obj instanceof Object)//true
/*
obj就是一个空的Object对象,记住,是对象,和new Object一样,对象的隐式原型obj.__proto__就是Object的显式原型,
已经到达,为true,该情况比较特殊,得记住。
*/
console.log(fn instanceof Object)//true
/*
把function fn(){}看成var fn = new Function();之后可以得出,fn.__proto__是Function的原型
(即Function.prototype),再接着fn.__proto__.proto__就是Object的原型(Object.prototype),已到达,为true,具体可见原型链示意图1
*/
console.log(obj instanceof Function)//false
/*
obj是个空对象,obj.__proto__就是Object的原型对象(Object.prototype),obj.__proto__.proto__
就是null,终止,没有到达Function.prototype,所以false
*/
如果尝试访问对象的显式指向(prorotype)的原型对象呢?有吗?对象没定义这个属性之前都是undefined,而__proto__是隐式已经定义好的。
接下来来看看一些例子:
/*
测试题1
*/
function A() {
}
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
解释:
声明函数时创建的function对象A(),同时创建原型对象用A.prototype显式指向它,这个原型对象再隐式指向Object的显式原型对象(Object.prototype),具体见原型链示意图1。
接着这个A()的显式指向的原型对象里面添加一个属性n为1。
声明b指向实例对象A,这个对象b的__proto__就是A.prototype(A的显式指向的原型对象),见原型链示意图1
现在要开始改变了,A()的显式指向的原型对象变了!!!意味着这个工厂以后创建对象的原型对象都变了,但是原来的原型对象还有东西去指着它的,那就是刚刚的b,b对象的隐式指向的原型对象被A()抛弃了,里面还有刚刚添加的n为1呢。
新工厂造新对象c,隐式指向的原型对象就是新的{n:2, m:3}
所以最后控制台打印的是1 undefined 2 3
如果被function A() 抛弃的原型对象没有被b隐式指向呢??
function A() {
}
A.prototype.n = 1;
A.prototype = {
n: 2,
m: 3
};
var b = new A();
var c = new A();
console.log(b.n, b.m, c.n, c.m);
那么答案就是2 3 2 3
来看看测试题2
/*
测试题2
*/
function F (){}
Object.prototype.a = function(){
console.log('a()')
}
Function.prototype.b = function(){
console.log('b()')
}
// 下面操作均可以看原型链示意图1得出解释
var f = new F()
f.a() // 打印a()
// f.b() // 会报错,b not a function
F.a() // 打印a()
F.b() // 打印b()
==============Talk is cheap, show me the code================