javascript原型链容易混淆的相关知识

讲解一下关于原型链的知识。

instanceof

语法:

1
object instanceof constructor;

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
简单来说就是检查constructor.prototype是否出现在object.__proto__上面。
注意:这个对比的不是输入时的参数,而是他们的原型,这也是和isPrototypeOf的区别

听起来是不是很奇怪?为什么是constructor.prototype是否出现在object.__proto__上面,而不是object.__proto__出现在constructor.prototype上面?
大家都知道这个是用来判断继承或者一个实例是否是某个类的。
这就要想清楚继承的真正含义,别被想当然给误解了。
类 A 继承 Z,那么 A 的实例 a 应该都“属于”A 和 Z,也就是 instaceof 都是 true。
继承其实是子类包含父类,而不是父类包含子类。
那为什么说子类属于父类呢?
这个是从不同概念上来说的,子类属于父类是从抽象的概念上来说的,上面说的包含是从内容上面来说。比如男人女人都属于人类,但是男人包含了所有人类这个层面抽象的所有内容。

1
2
从抽象概念上说:子类是父类的一部分,属于父类。
从内容的角度出发:子类的内容包含了抽象的父类的内容。

isPrototypeOf

isPrototypeOf() 方法用于测试一个对象是否存在于另一个对象的原型链上。

1
prototypeObj.isPrototypeOf(object)

检测prototypeObj是否在object的原型链上。

注意:这个做对比时,就是prototypeObj本身,而不是他的原型,这是和instanceof的区别。写是o,那对比的就是o,写的是o.__proto__,对比的就是o.__proto__

1
2
3
4
5
6
7
function C(){}
let c=new C();
let o=new Object();

o.isPrototypeOf(c); // false, 因为o不在c.__proto__上
o.__proto__.isPrototypeOf(c); // true
o.__proto__.isPrototypeOf(C); // true

Object.create

1
2
let o=Object.create(proto[, propertiesObject])
o.__proto__===proto

Object.create()方法创建一个新对象o,使用现有的对象proto来提供新创建的对象o__proto__

Object.getPrototypeOf

Object.getPrototypeOf() 方法返回指定对象的原型(内部[[Prototype]]属性的值)

1
let proto = Object.getPrototypeOf(object);

proto就是object__proto__

new 运算符

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。new 关键字会进行如下的操作:

  • 创建一个空的简单 JavaScript 对象(即{});
  • 链接该对象(即设置该对象的构造函数)到另一个对象 ;
  • 将步骤 1 新创建的对象作为 this 的上下文 ;
  • 如果该函数没有返回对象,则返回 this。
1
2
3
4
5
6
7
8
9
function Car() {
this.name = "zhangsan";
return {
name: "lisi",
};
}

let car = new Car();
car.name; // lisi

因为函数有自己的返回值,所以实例化的对象就是返回的对象,而不是 this;

1
2
3
4
5
6
7
8
function Car(name) {
this.name = name;
}
let car1 = new Car("dongfeng");
let car2 = Object.create(car1);
let car3 = Object.create(car1.__proto__);
car2.name; // dongfeng
car3.name; // undefined;

这里解释为什么car2name有值,car3没有;
首先要明白new运算符的执行过程;从上面定义我们知道,创建的car1是有属性name的,car1__proto__是指向Car.prototype,这上面是没有name的。
然后需要明白Object.create的使用,它是把创建的对象的__proto__指向了传入的对象。
因此car2.__proto__===car1,因此有name属性;car3.__proto__指向car1.__proto__也就是Car.prototype,所以没有name属性。

文章作者: wenmu
文章链接: http://blog.wangpengpeng.site/2020/01/09/javascript%E5%8E%9F%E5%9E%8B%E9%93%BE%E5%AE%B9%E6%98%93%E6%B7%B7%E6%B7%86%E7%9A%84%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 温木的博客
微信打赏