原型、构造函数、实例、原型链的关系

415 阅读3分钟

1、概要

  • 本文主要介绍了原型链的相关知识
  • 创建对象的方法
  • 原型、构造函数、实例、原型链的关系
  • instanceof的原理
  • new运算符

2、创建对象的方法

// 创建对象的方式
// (1) 字面量 
var obj1 = { name: 'obj1' }; 
var obj2 = new Object({ name: 'obj2' }); // 不是字面量,但结果和字面量等同
// (2) 构造函数
var Fn = function(name) {
  this.name = name;
}
var obj3 = new Fn('obj3');
// (3) Object.create
var parentObj = { name: 'obj4'};
var obj4 = Object.create(parentObj);

3、原型、构造函数、实例、原型链

// 原型、构造函数、实例、原型链的关系
// 1、实例 ==> 1. 对象就是一个实例,就有_proto_属性
//             2. 实例通过_proto_原型链找到prototype原型对象,prototype原型对象的属性被所有实例共享。
// 2、构造函数 ==> 1.可以通过new运算符生成一个实例。
//                 2.任何函数都可以作为构造函数。
//                 3.只要被new运算符使用过的函数就是一个构造函数
// 3、原型 ==> 1. 函数都有prototype属性,prototype属性的值就是一个初始化的原型对象。
//             2. 原型对象有个constructor和_proto_属性,constructor是一个构造函数。
//             3. Fn.prototype.constructor === Fn   // constructor函数指向构造函数本身。通过constructor把原型对象和构造函数关联。
// 4、原型链 ==>1. 对象有_proto_属性(函数也是对象,所以函数也有_proto_属性)
//              2. 实例通过_proto_原型链找到prototype原型对象,如果找不到,则通过原型对象的_proto_继续往上找,一直到顶层。
// 5、关系:==> 1. Fn.prototype.constructor === Fn  // 构造函数原型的constructor属性指向构造函数本身
//              2. obj3.__proto__.constructor === Fn
//              3. obj3.__proto__.constructor === Fn.prototype.constructor
//              4. obj3.__proto__ === Fn.prototype  // 修改prototype的属性, __proto__也会修改,同理也是

4、instanceof的原理

// instanceof ==> 1. 判断实例对象的__proto__和构造函数的prototype属性指向同一个引用地址
                    (并不能判断一个对象是不是一个构造函数直接生成的实例),
//                2. obj3 instanceof Fn  // true
//                3. obj3 instanceof Object  // true,由于 Fn instanceof Object === true
//                4. 如何准确判断一个对象是不是一个构造函数直接生成的实例对象(通过constructor): 
//                   obj3.__proto__.constructor === Fn.prototype.constructor // true
//                   obj3.__proto__.constructor === Object.prototype.constructor // false

5、new运算符

var obj3 = new Fn('obj3');
obj3实例对象在创建过程
1. new运算符会先创建一个新对象,它继承自Fn.prototype。
2. 构造函数Fn被执行,相应的参数会被传入,this会被指向这个新的实例。
3. 在不传参数时,new Fn等同于new Fn()
4. 如果Fn返回了一个对象,那么这个对象会取代new出来的对象。
5. 如果构造函数没有返回对象,那么new出来的对象就是最终的结果。

new运算符的工作原理,用代码模拟
var newTest = function(fn) {
    var initObj = Object.create(fn.prototype);
    var obj = fn.call(initObj);
    if(typeof obj === 'object') {
      return obj;
    } else {
      return initObj;
    }
}
var Fn = function() {
  // this.name = 'obj3', 最后newTest(Fn)返回的结果完全等同。
  return {
    name: 'obj3';
  }
}
newTest(Fn)

6. 总结

  1. 自己也是在处在深入学习和理解的阶段,如有错误之处,请指正。
  2. 后续为将继续分享继承以及面向对象的相关内容。
  3. 未完待续。