全回顾扫盲js之原型链一

对象的三种创建方式

  • 一、字面量或者new Object
  • 二、构造函数
  • 三、Object.create

prototype和__proto__的区别

  • prototype:每个函数对象才有的属性,它的constructor指向该函数。每个函数fn一创建,就附带出一个prototype属性,这个属性的值是一个对象。可以理解成这样:fn.prototype = {constructor: fn}
  • __proto__:每个对象都有的属性,指向它的构造函数的原型对象。

所以,按下面这个方式创建对象,得出b.__proto__ === a.prototype。如果按照父子级函数来说,__proto__是子函数指向父函数的原型对象的指针

var a = function () {
}
a.prototype.name = '小明'
var b = new a()
console.log(b.__proto__ === a.prototype)
  

原型链的流动方向

首先明确一下,函数对象跟原型对象的父级并不是一个。我是懵逼了很久才测试出来的。函数是由function Function创建的,而原型对象是由function Object创建的。而且function 和prototype对象都有自己的__proto__属性

函数对象的流动方向

  • 子函数对象.__proto__ --> 父函数对象的原型对象,父函数对象的原型对象.constructor --> 父函数对象:子函数对象.__proto__ === 父函数对象.prototype
  • 父函数对象.__proto__ --> Function函数对象的原型对象function () { [native code] }:这里是函数对象创建的顶端了,顶层就是Function,会不停循环下去
  • Function对象的原型对象.__proto__ --> Object对象的原型对象:Function对象是Object对象的子级
  • null.__proto__ --> 报错 TypeError: b.__proto__.__proto__.__proto__ is null。null是空对象,所以不存在父级对象,是原型链的顶层。

原型对象的流动方向

  • 子函数对象.__proto__ -> 父函数对象的原型对象
  • 父函数的原型对象.__proto__ -> Object的原型对象:父函数的原型对象直接指向Object的原型对象
  • Object的原型对象.__proto__ -> null:Object的原型对象指向空对象null
  • null的原型对象.__proto__ -> 报错Cannot read property '__proto__' of null:null是空对象,没有属性

总结发言(有些用词可能不恰当,但为了简单直接,不咬文嚼字)

  • 原型链的终端是null,null创建Object,Object创建Function对象和父函数的原型对象,Function创建父函数
  • 每个函数对象有指向原型对象的prototype和指向父原型对象的__proto__,每个原型对象有指向函数的constructor和指向父级原型对象的__proto__。然而,他们指向的并不相同。函数对象全都指向Function,而原型对象是指向有价值的父级。所以叫原型链不叫函数链。。。
function a () {
}
a.prototype.name = '小明'
var b = new a()

console.log(b.__proto__)                                                    // Object {name: "小明", constructor: function}
console.log(b.__proto__.constructor)                                        // function a() {}
console.log(b.__proto__ === a.prototype)                                    // true
console.log(b.__proto__.constructor.__proto__)                              // function () { [native code] }
console.log(b.__proto__.constructor.__proto__.constructor)                  // function Function() { [native code] }
console.log(b.__proto__.constructor.__proto__.constructor.__proto__)        // function () { [native code] }
console.log(b.__proto__.constructor.__proto__.constructor.__proto__.__proto__)    // Object {__defineGetter__: function,__lookupSetter__: function…}
console.log(b.__proto__.constructor.__proto__.constructor.__proto__.__proto__ === b.__proto__.constructor.__proto__.constructor.prototype.__proto__)    // true
console.log(b.__proto__.constructor.__proto__.constructor.__proto__.__proto__.constructor)    // function Object() { [native code] }

console.log('------------------------------------')
console.log(b.__proto__)                            // Object {name: "小明", constructor: function}
console.log(b.__proto__.__proto__)                  // Object {__defineGetter__: function,__lookupSetter__: function…}
console.log(b.__proto__.__proto__.constructor)      // function Object() { [native code] }
console.log(b.__proto__.__proto__.__proto__)        // null
// console.log(b.__proto__.__proto__.__proto__.__proto__)        // Cannot read property '__proto__' of null

console.log('-------------原型链还是函数链--------------------------')
function c () {}
c.prototype.name = 'xiaoming'
function d () {}
d.prototype = new c()
d.prototype.age = '23'
console.log(d.prototype.__proto__)  // 指向父级
console.log(d.__proto__.constructor)    // 还是指向Function
  

随机浏览