附上别人总结的例子,方便查阅: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();

       那么function Object(){...}也可以看成var Object = new Function();所以Object可以看成是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================