JavaScript原型链和instanceof运算符的暧昧关系

简介:

时间回到两个月前,简单地理了理原型链、prototype以及__proto__之间的乱七八糟的关系,同时也简单了解了下typeof和instanceof两个运算符,但是,anyway,试试以下两题:

console.log(Function instanceof Function);
console.log(String instanceof String);

如果无法得出准确答案,跟着楼主一起温故而知新吧。

温故

我们经常用typeof运算符来判断一个变量的类型,也确实挺好用,能判断出number、boolean、string,但是对于 object的判断能力一般,比如Array和null的判断结果都是object,而且对于new的一些对象,比如new String(),new Number()等的结果都是object,这样下来就有个问题,无法更细致地判断对象实例,这时就需要instanceof出马了。顾名思 义,instanceof是判断一个对象是否为某一构造函数实例的运算符,这样下来,对于new出来的变量,到底是number、string还是别的什 么玩意,就有了进一步的判断认识了。看起来很简单,其实不然,上面的两题就是小试牛刀了,先放着,再来回顾下原型链。

JavaScript中一切皆为对象,所有对象都有个__proto__属性值(即原型),可能某些坑爹浏览器下不支持,暂且不管,某对象的该 属性的取值是该对象的构造函数的prototype值,作用就是对于某一个类型的对象,不用重复定义某种方法,譬如说对于对象[1,2,3],显然这是个 数组对象,它具有pop、push等方法,但是并不是说它本身就具有这些方法,而是它的构造函数Array函数所具有,而该对象的__proto__取值 就是Array函数的prototype值,so如果本身并不具有pop方法,就会从它的__proto__中寻找,即所谓的原型链;而该条链的末端就是 Object,因为一切对象都是由Object构造而成,而Object.prototype.__proto__规定指向null。

文字的描述永远是苍白无力的,举个简单的例子:

 
  1. var fun = function(){ 
  2.   this.a = 1
  3. }; 
  4.   
  5. fun.prototype.b = 2
  6. var obj = new fun(); 
  7. obj.a; //1 
  8. obj.b; //2

网上盗的例子和图,仔细看就会发现说的很清楚。

知新

接下来看看instanceof运算符。

instanceof的常规用法是判断a是否是b类型:

 
 
  1. console.log(true instanceof Boolean); // false  
  2. console.log(new Number(1instanceof Number); // true 

instanceof还能判断父类型:

 
  1. function Father() {} function Child() {} Child.prototype = new Father(); var a = new Child(); console.log(a instanceof Child);  // true 
  2. console.log(a instanceof Father); // true 

Child构造函数继承自Father,实例a是Child构造的无疑,但是为何也是Father的实例呢?其实instanceof运算符的内核可以简单地用以下代码描述:

 
  1. function check(a, b) {   while(a.__proto__) {     if(a.__proto__ === b.prototype)       return true;     a = a.__proto__;   }   return false; } function Foo() {} console.log(Object instanceof Object === check(Object, Object)); // true 
  2. console.log(Function instanceof Function === check(Function, Function)); // true 
  3. console.log(Number instanceof Number === check(Number, Number)); // true 
  4. console.log(String instanceof String === check(String, String)); // true 
  5. console.log(Function instanceof Object === check(Function, Object)); // true 
  6. console.log(Foo instanceof Function === check(Foo, Function)); // true 
  7. console.log(Foo instanceof Foo === check(Foo, Foo)); // true 

简单地说,a如果是b的实例,那么a肯定能使用b的prototype中定义的方法和属性,那么用代码表示就是a的原型链中有b.prototype取值相同的对象,于是顺着a的原型链一层层找就行了。

另外值得注意的是,String Number Boolean 以及Function等都是函数,而函数则是统一由Function构造而来的,so它们和任何单纯的函数一样,能用Function上的原型属性:

 
 
  1. Function.prototype.a = 10; console.log(String.a);  // 10 

最后来简单讲讲最开始的两道题吧。

 
  1. // 为了方便表述,首先区分左侧表达式和右侧表达式 
  2. FunctionL = Function, FunctionR = Function; // 下面根据规范逐步推演 
  3. O = FunctionR.prototype = Function.prototype L = FunctionL.__proto__ = Function.prototype // 第一次判断 
  4. O == L // 返回 true
 
  1. // 为了方便表述,首先区分左侧表达式和右侧表达式 
  2. StringL = String, StringR = String; // 下面根据规范逐步推演 
  3. O = StringR.prototype = String.prototype L = StringL.__proto__ = Function.prototype // 第一次判断 
  4. O != L // 循环再次查找 L 是否还有 __proto__ 
  5. L = String.prototype.__proto__ = Object.prototype // 第二次判断 
  6. O != L // 再次循环查找 L 是否还有 __proto__ 
  7. L = String.prototype.__proto__ = null 
  8. // 第三次判断 
  9. L == null 
  10. // 返回 false 



作者:韩子迟

来源:51CTO

相关文章
|
3月前
|
JavaScript 前端开发
深入理解JavaScript中的原型链
本文将深入探讨JavaScript中的原型链机制,从根本上理解它的工作原理以及在开发中的应用。我们将介绍原型链的概念、如何创建和使用原型、原型链的继承机制以及一些常见的原型链相关问题。通过对原型链的详细解析,读者将能够更好地理解JavaScript中的继承、原型对象和原型链之间的关系,提高代码的质量和可维护性。
|
3月前
|
存储 前端开发 JavaScript
揭秘原型链:探索 JavaScript 面向对象编程的核心(下)
揭秘原型链:探索 JavaScript 面向对象编程的核心(下)
揭秘原型链:探索 JavaScript 面向对象编程的核心(下)
|
3月前
|
前端开发 JavaScript 开发者
揭秘原型链:探索 JavaScript 面向对象编程的核心(上)
揭秘原型链:探索 JavaScript 面向对象编程的核心(上)
揭秘原型链:探索 JavaScript 面向对象编程的核心(上)
|
3月前
|
存储 JavaScript 前端开发
原型链:揭开JavaScript背后的神秘面纱
原型链:揭开JavaScript背后的神秘面纱
|
3月前
|
JavaScript 前端开发 Java
JavaScript基础语法(运算符)
JavaScript基础语法(运算符)
32 0
|
3月前
|
前端开发 JavaScript
JavaScript中的原型和原型链
JavaScript中的原型和原型链
|
3月前
|
JavaScript 前端开发
JavaScript原型,原型链
JavaScript原型,原型链
|
23天前
|
JavaScript
js开发:请解释什么是ES6的扩展运算符(spread operator),并给出一个示例。
ES6的扩展运算符(...)用于可迭代对象展开,如数组和对象。在数组中,它能将一个数组的元素合并到另一个数组。例如:`[1, 2, 3, 4, 5]`。在对象中,它用于复制并合并属性,如`{a: 1, b: 2, c: 3}`。
12 3
|
1月前
|
JavaScript 前端开发
在JavaScript中,如何优化原型链的性能?
在JavaScript中,如何优化原型链的性能?
13 2
|
1月前
|
JavaScript 前端开发
谈谈对 JavaScript 中的原型链的理解。
谈谈对 JavaScript 中的原型链的理解。
15 1