JS核心理论之《构造函数、实例、原型与原型链》

345 阅读3分钟

构造函数、原型、实例

构造函数:用来在创建对象时初始化对象。特点:构造函数名一般为大写字母开头;与new运算符一起使用来实例化对象。

原型:构造函数在创建的过程中,系统自动创建出来与构造函数相关联的一个空的对象。可以由构造函数.prototype来访问到。

实例:通过构造函数创建出来的对象。

构造函数、原型对象、实例化对象三者的关系:

image

示例:

function Person() {

}
// prototype是函数才会有的属性
Person.prototype.name = 'Kevin';
var p = new Person();

console.log(p.__proto__ === Person.prototype); // true
console.log(Person === Person.prototype.constructor); // true

//当获取 p.constructor 时,其实 p 中并没有 constructor 属性,当不能读取到constructor 属性时,
//会从 p 的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:
console.log(p.constructor === Person); // true
console.log(p.constructor === Person.prototype.constructor); // true
  1. 在实例化对象p的过程中,系统就自动创建出了构造函数的原型,即 Person.prototype
  2. 每个原型都有一个 constructor 属性指向关联的构造函数;
  3. 每个实例对象(除了 null )都具有的一个属性,叫__proto__ ,这个属性会指向该对象的原型;
  4. prototype是构造函数的属性,__proto__是实例对象的属性,constructor是原型的属性。

原型链

原型链:每一个对象都有自己的原型对象,原型对象本身也是对象,原型对象也有自己的原型对象,这样就形成了一个链式结构,叫做原型链。 在上面这个例子中的p对象的原型链结构图如下:

p对象----->Person.prototype------->Object.prototype--------->null

对这个实例化对象而言,访问对象的属性,是首先在对象本身去找,如果没有,就会去他的原型对象中找,一直找到原型链的终点; 如果是修改对象的属性,如果这个实例化对象中有这个属性,就修改,没有这个属性就添加这个属性。

image

new与instanceOf

new A()

使用new命令时,它后面的函数依次执行下面的步骤:

  1. 创建一个空对象,作为将要返回的对象实例。
  2. 将这个空对象的原型,指向构造函数的prototype属性。
  3. 将这个空对象赋值给函数内部的this关键字。
  4. 开始执行构造函数内部的代码。

可表示如下:

var obj = {}; // 创建一个空对象
obj.__proto__ = 构造函数.prototype;
构造函数.call(this); // 绑定this
...
return obj;

A instanceOf B

主要的实现原理: 就是只要右边变量的 prototype 在左边变量的原型链上即可。 因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false,告诉我们左边变量并非是右边变量的实例.

类型判断

简单来说,我们使用 typeof 来判断基本数据类型是 ok 的,不过需要注意当用 typeof 来判断 null 类型时的问题, 如果想要判断一个对象的具体类型可以考虑用 instanceof,但是 instanceof 也可能判断不准确,比如一个数组,他可以被 instanceof 判断为 Object。 所以我们要想比较准确的判断对象实例的类型时,可以采取 Object.prototype.toString.call 方法