javascript 理解 typeof, instanceof and constructor


   我们假设要写个isArray() 的方法,当然ecmascript5 已经添加了这个方法,(>ie8)
   首先我们使用typeof:
   在ECMAScript 中有5中基本数据类型,Undefined、Null、Boolean、Number、String,还有一种复杂的数据类型,即:Object

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object

   MDN Description:All objects in JavaScript are descended from Object; all objects inherit methods and properties from Object.prototype, although they may be overridden
   在javascript中,Object是‘祖先‘,所有objects都是Object的子,并从Object.prototype下继承属性和方法。

   使用typeof时要注意的就是typeof null = "object";   
    var arr=new Array();
    typeof arr === "object";//true
   显然只用typeof 是不行的,无论引用的是什么类型的对象,它都返回 "object"。然后我们就会想到instanceof或constructor
    arr instanceof Array; // true   
    arr.constructor === Array; // true

   但是在不同iframe下,就不行了!
    var iframe = document.createElement(‘iframe‘);   
    document.body.appendChild(iframe);   
    xArray = window.frames[window.frames.length-1].Array;   
    var arr = new xArray(1,2,3); // [1,2,3]   

    arr instanceof Array; // false   
    arr.constructor === Array; // false  


    MDN Description:Different scope have different execution environments. This means that they have different built-ins (different global object, different constructors, etc.).
    
    下面具体解释!
    先说constructor
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor
    MDN Description:All objects inherit a constructor property from their prototype。
    所有的objects 都从它们的prototype继承了constructor属性。而这个constructor指向了这个object本身,也就是所谓的构造函数!即 Array.prototype.constructor === Array
    所以上面的 arr.constructor === Array;

    但是在不同iframe下,由于每个iframe都有一套自己的执行环境,不同的执行环境具有不同的原型链, 接着上面的代码,xArray.prototype === Array.prototype  //false ,
    所以上面的 arr.constructor !== Array;   
    

    再说下instanceof,这个有点复杂,耐心看!

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof

    MDN Description:The instanceof operator tests presence of constructor.prototype in object prototype chain.
    instanceof 用来判断 构造函数的原型是否存在于 某个object的原型链上
    这句话翻译过来很难理解,说简单点,instanceof 用于判断一个变量是否是某个object的实例。
    我们来看看instanceof 的原理,这样就会理解那句话了!


    首先解释下原型,在 JavaScript 原型继承结构里面,规范中用 [[Prototype]] 表示对象隐式的原型,在 JavaScript 中用 __proto__ 表示,并且在 Firefox 和 Chrome 浏览器中是可以访问得到 


    这个属性的,但是 IE 下不行, 这个属性指向它的原型对象。在 JavaScript 里用 prototype 属性表示显示的原型,这个大家都知道;
    当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样一直找下去,你可以再Chrome下输入 


   一个对象,比如window,然后点开,在最下面就会看到__proto__,点开__proto__,最下面又有__proto__,这个就是javascript的原型链!
   关于__proto__,https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto


    让我们看下instance_of 的一段代码

 function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
     var O = R.prototype;// 取 R 的显示原型,即构造函数的原型(这里说构造函数是配合上面的英文)
     L = L.__proto__;// 取 L 的隐式原型
     while (true) { //循环查找object的原型链
     if (L === null) 
        return false; 
     if (O === L)// 构造函数的原型存在于 某个object的原型链上
        return true; 
     L = L.__proto__; //继续查找
    } 
 }

这段代码是一篇博客里copy的,应该是段伪代码!它很清楚的表达的instance_of的原理,也解释了上面的英文!

重新组织下语言,可以这样说: 如果‘类‘(构造函数)的原型与对象(object)原型链上的某一个原型是同一个对象,那么instanceof运算将返回true。
理解了原理,我们再回到上面的 var arr=new Array();
由于Array.prototype === arr.__proto__;//true
所以 arr instanceof Array; // true  
在不同iframe下,arr instanceof Array; // false ,这个在constructor里已经解释了,即:不同的执行环境具有不同的原型链!

上面是借isArray来分析 typeof, instanceof and constructor 这三个东东!

但是isArray到底该怎么来实现的!查看了下jquery的源码,和mdn的大同小异!

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray

主要原理是利用了Object.prototype.toString()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
MDN Description:If this method is not overridden in a custom object, toString() returns "[object type]"
如果这个方法没有被重载的话,它会返回"[object type]",即可以得到对应的类型!(更详细的返回值可以通过http://www.ecma-international.org/ecma-262/5.1/http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf来查看)
Object.prototype.toString()可以判断所有的内置类型,这里只是用Array举例而已!
看下面代码!

  var isArray = function (vArg) {
    return Object.prototype.toString.call(vArg) === "[object Array]";
  };


call改变toString的this引用为待检测的对象,返回此对象的字符串表示,然后对比此字符串是否是‘[object Array]‘,以判断其是否是Array的实例。
也许你要问了,为什么不直接o.toString()?嗯,虽然Array继承自Object,也会有toString方法,但是这个方法已经被改写了!不能返回type;详情看https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/toString或上面的http://www.ecma-international.org/ecma-262/5.1


参考博客:
http://www.ibm.com/developerworks/cn/web/1306_jiangjj_jsinstanceof/   //instanceof
http://www.cnblogs.com/qiantuwuliang/archive/2011/01/08/1930548.html  //constructor 
http://blog.csdn.net/isea533/article/details/7248520  //isArray

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。