JS 原型(二)new 调用和检查类的关系

109 阅读2分钟

这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战

hi 我是小十七_,新年快乐,今天是大年初三,之前整理了 JS 原型链相关的知识,整理出了几篇文章,在这里分享给大家。这一篇文章讲的是,new 调用和检查类的关系。

new 调用函数

function Foo(name){
	this.name = name;
}
Foo.prototype.getName = function(){
	return this.name;
}
var a = new Foo();
// 获取 a 的原型,链接到了 Foo.prototype
Object.getPrototypeOf(a) === Foo.prototype;   // true
var b = new Foo('abc');
b.getName();   // abc

知识点:

  1. 在被 new 操作符调用之前,Foo 和普通函数没有任何不同
  2. 使用 new 调用函数之后,进行了四步:
    1. 创建一个新对象
    2. 将新对象的 [[Prototype]] 链接到 Foo.prototype
    3. 新对象被绑定到函数调用的 this,所以函数内部的this,指向新对象
    4. 如果 Foo 没有返回值,或者没有返回其他对象,则返回新对象。

避免使用 constructor

function Foo(){};
var a = new Foo();
Foo.prototype.constructor === Foo;
a.constructor === Foo;

Foo.prototype 默认情况下有一个属性 constructor,指向 Foo 本身,所以 a.constructor,a 本身并没有 constructor 这个属性,所以通过原型链找到 Foo.prototype 的 constructor,但是这并不可信:

function Foo(){}
Foo.prototype = {};  // 重写了 Foo.prototype
var a = new Foo();
a.constructor === Foo;  // false
a.constructor === Object;  // true

Foo.prototype 被重写后,a.constructorFoo.prototype 找不到 constructor 属性,于是沿着原型链继续向上找,找到了 Object.prototype.constructor。 默认的 constructor 属性是一个不可枚举的属性(enumerable: false),可以被修改,所以使用 a.constructor 是不可靠不安全的,尽量避免使用它。

检查类之间的关系

想要检查一个对象的整条原型链中是否有指向Foo.prototype的对象

function Foo(){
}
var a = new Foo();
a instanceof Foo;  // true
a instanceof Object; // true,Foo.prototype 的原型指向 Object.prototype
var arr = [];
var obj = {};
arr instanceof Array; // true, arr 原型指向 Array.prototype
arr instanceof Object; // true, Array 函数的原型指向 Object.prototype
obj instanceof Array; // false, obj 原型指向 Obejct.prototype

所以,可以用 instanceof Array 判断数组

var obj = Object.create(null);
obj instanceof Object;  // false

使用 Object.create(null) 创建的对象没有[[Prototype]] instanceof 只能判断对象和函数之间的关系,两个对象的话不能判断。

在用 bind 生成硬绑定函数时,新函数的prototype直接复制的目标函数的prototype,所以用instanceof的话,直接用的是目标函数的prototype