JS原型理解

原型链是整个JS面向对象的基础
在理解原型链之前先来谈谈JS创建对象的几种方式

//字面量方式
var a1 = {name:'a1'}
var a2 = new Object({name:'a2'})
//构造函数方式
var F = function(name) {
  this.name = name
}
var a3 = new F('a3')
//Object.create()方式
var o = {name:'a4'}
var a4 = Object.create(o)
console.log(a1,a2,a3,a4)
//{name: "a1"}
//{name: "a2"}
//{name: "a3"}
//{}

可以看到输出了4个对象,a1和a2看起来一样,但是a3和a4就有一些不一样了。

  1. a1和a2创建的时候原型对象指向Object;
  2. a3是F构造函数的实例,所以指向的是F构造函数(当任何一个函数被new使用了它就是一个构造函数);
  3. a4输出看不到name属性,但是可以通过a4.name获取到name值(这里能获取到就是因为如果在对象内找不到name时JS会自动去原型链上一层一层往外找,所以就找到了proto属性里的name,当找到最外层Object的原型对象时没有找到则会结束查找);
    在浏览器控制台输出对象时展开会发现有粉色的protoprototype这两个属性,这就是原型对象。
    区别在于对象上只有proto属性,而函数有protoprototype这两个属性。

注意:prototype只有函数上有,proto只有对象上有,因为JS中函数也算是一种对象,所以在函数上也有proto属性。


原型、构造函数、实例相互关系:

构造函数指F函数,实例指a3

原型.png

任何一个实例对象可以通过原型链找到它上层的属性和方法,都是共享的。
注意:函数F是Function的实例

F.__proto__===Function.prototype
//true

instanceof原理:

instanceof用来判断实例是否为某个对象的实例。

其原理就是根据原型链来判断。

流程如下:

instanceof.png

比较实例对象的proto和构造函数的prototype是否相同,如果相同则为真。

a3 instanceof F
//等价
a3.__proto__ === F.prototype
//true
//只要是在原型链上的构造函数,都会返回真
a3 instanceof Object
//等价
a3.__proto__.__proto__ === Object.prototype
//true

因为instanceof不够精确,所以可以使用constructor来判断是否为实例。

a3.__proto__.constructor === F
//true
a3.__proto__.constructor === Object
//false

new运算符:

foo为构造函数

  1. 一个新对象被创建,它继承于foo.prototype。
  2. 构造函数被执行。执行的时候,相应的参数会被传入,同时上下文(this)会被指定为这个新实例。new foo等同于 new foo(),只能用在不传参的情况。
  3. 如果构造函数返回了一个对象,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为步骤1创建的对象。
var new2 = function (func) {
  var o = Object.create(func.prototype)
  var k = func.call(o)
  if (typeof k === 'object') {
    return k
  } else {
    return o
  }
}
var a5 = new2(F)
a5 instanceof F
//true
a5.__proto__.constructor === F
//true

Object.create参考

你可能感兴趣的:(JS原型理解)