JavaScript instanceof運算符深刻分析

前言

若是你要開發一個複雜的產品,那麼確定少不了使用面向對象機制,固然也避不開 Javascript 裏面的繼承,instanceof 運算符是原生 Javascript 語言中用來判斷實例繼承的操做符。因此咱們有必要深刻理解該運算符!javascript

instanceof 運算符簡介

  在 JavaScript 中,要判斷某個變量的類型,咱們第一個想起的就是 typeof 運算符,可是在使用 typeof 運算符的時候 ,只要是引用類型存儲的變量,不管你引用的是什麼類型的對象,統一返回 「object」 ,這就是一個大問題,咱們如何判斷這個對象是屬於哪一個類型的呢? ECMAScript 引入了在Java 中的instanceof運算符來解決這個問題,instanceof與typeof均可以檢測數據類型,instanceof 運算符與 typeof 運算符的不一樣點是:要求開發者明確的確認檢測對象爲某特定類型的數據java

舉例說明分析

Javascript 變量類型

  這個網上有不少種說法,說法不少的緣由也很簡單,就是由於在JS一切皆對象,一切引用類型都是繼承於 Object 類型的。我在這裏分爲幾大類瀏覽器

undefiend 沒有定義數據類型
 number 數值數據類型 例如 10或者1或者5.5
 string 字符串數據類型用來描述文本 例如 "你的姓名"
 boolean 布爾類型 true|false  不是正就是反,是或者否,有或者沒有
 object 對象類型 複雜的一組描述信息的集合
 function 函數類型

這麼分的根據是什麼呢?很簡單,就是經過 typeof 來區分的函數

function Fun(){}
var unde = typeof abc;    // 基本類型
var numb = typeof 300;    // 基本類型
var str  = typeof "hello";    // 基本類型
var bool = typeof true;       // 基本類型
var func = typeof function(){}   // 引用/對象 類型
var obje = typeof new String("hello");   // 引用/對象 類型
var nul = typeof null;    // 引用/對象 類型
var obj = typeof new Fun()   // 引用/對象 類型
console.log('\n',unde,'\n',numb,'\n',str,'\n',bool,'\n',func,'\n',obje);
console.log('\n',obj,'\n',nul)

結果爲:
answerspa

從中能夠看出,typeof 就只能返回這六種數據類型,因此基本類型就肯定爲這六種。其實函數 function 也是對象類型,這個問題後面會講到的。
注意基本變量類型不是對象類型,只有基本包裝類型纔是對象類型。因此 str instanceof Object/String 都是 falseprototype

instanceof 舉例

常規用法

var StringObje = new String("instanceof");
console.log(StringObje instaceof String); // 輸出爲true

這段代碼問的是,變量 StringObje 是否是 String 對象的實例,答案爲 true,很顯然是的 , typeof 只會返回 "Object",因此 instanceof 仍是有用的,固然你會發現 StringObje instanceof Object 也是true
一般來說使用 instanceof 就是判斷一個實例是否屬於某種類型翻譯

// 判斷 foo 是不是 Foo 的實例
function Foo(){}
var foo = new Foo();
console.log(foo instaceof Foo)  // true

instanceof 在繼承中關係應用

// 判斷 a 是不是A類的實例,和是不是其父類 AFather 的實例
function AFather(){}
function A(){}
AFather.prototype = new A(){};  // js原型繼承
var a = new A();
console.log(a instanceof A)  //true
console.log(a instanceof AFather)   //true

在多層繼承中,仍然適用。code

instanceof 複雜用法

function Foo(){}
console.log(Object instanceof Object);//1  true 
console.log(Function instanceof Function);//2  true 
console.log(Number instanceof Number);//3  false 
console.log(String instanceof String);//4  false 
console.log(Function instanceof Object);//5   true 
console.log(Foo instanceof Function);//6  true 
console.log(Foo instanceof Foo);//7  false

對上面的結果有沒有感受到奇怪,奇怪也正常,由於確實挺奇怪的!
對上面的分析,首先要看看,你檢測的究竟是什麼?對象

console.log(Object,Function,String,Number,Foo);
  /***
  *  結果以下
  *   function Object() { [native code] } 
  *   function Function() { [native code] } 
  *   function String() { [native code] } 
  *   function Number() { [native code] } 
  *   function Foo(){}
  */

這已經很明顯了,全部的檢測對象都是一個函數,那麼一定屬於函數類型和對象類型,只剩下3,4,7有問題了,那麼爲何是 false 呢?你想一想,Foo函數是Foo的實例嗎?顯然不是啊,同理,String和Number函數也不是其自己的實例,new Func() , 這個纔是實例對象。
想完全明白其中奧妙,必需要了解語言規範原型繼承機制繼承

規範中 instanceof 運算符定義

能夠參考這個網址 :instanceof 語法
  規範定義很晦澀,並且看起來比較複雜,涉及到不少概念,但把規範翻譯成 JavaScript 代碼卻很簡單,以下:

function instance_of(L, R) {    //L 表示左表達式,R 表示右表達式
  var O = R.prototype;           // 取 R 的顯示原型
  L = L.__proto__;               // 取 L 的隱式原型
  while (true) { 
    if (L === null)  return false;
    if (O === L)  return true;   // 這裏重點:當 O 嚴格等於 L 時,返回 true 
    L = L.__proto__; 
  } 
 }

Javascript 原型繼承機制

  本文主要在分析 JavaScript instanceof 運算符,對於 JavaScript 的原型繼承機制再也不作詳細的講解,下面參考來自http://www.mollypages.org/mis... 的一張圖片,此圖片詳細的描述了 JavaScript 各類對象的顯示和隱式原型鏈結構。
  由其涉及顯示原型和隱式原型,因此下面對這兩個概念做一下簡單說明。在 JavaScript 原型繼承結構裏面,規範中用 [[Prototype]] 表示對象隱式的原型,在 JavaScript 中用 __proto__ 表示,而且在 Firefox 和 Chrome 瀏覽器中是能夠訪問獲得這個屬性的,可是 IE 下不行。全部 JavaScript 對象都有 __proto__ 屬性,但只有 Object.prototype.__proto__ 爲 null,前提是沒有在 Firefox 或者 Chrome 下修改過這個屬性。這個屬性指向它的原型對象。 至於顯示的原型,在 JavaScript 裏用 prototype 屬性表示,這個是 JavaScript 原型繼承的基礎知識,在這裏就不在敘述了。
原型結構圖
這個圖片很好地表達了js原型鏈的關係,要仔細去看,跟着箭頭一步一步分析。

上述複雜問題的推演過程

若是你理解了 javascript 原型鏈,那麼這個問題就簡單了!
下面將詳細講解 Object instanceof Object,Function instanceof Function 和 Foo instanceof Foo 三個示例,其它示例讀者可自行推演。

1. Object instanceof Object
// 爲了方便表述,首先區分左側表達式和右側表達式
 ObjectL = Object, ObjectR = Object; 
 // 下面根據規範逐步推演
 O = ObjectR.prototype = Object.prototype 
 L = ObjectL.__proto__ = Function.prototype 
 // 第一次判斷
 O != L 
 // 循環查找 L 是否還有 __proto__ 
 L = Function.prototype.__proto__ = Object.prototype 
 // 第二次判斷
 O == L 
 // 返回 true
2. Function instanceof Function
// 爲了方便表述,首先區分左側表達式和右側表達式
 FunctionL = Function, FunctionR = Function; 
 // 下面根據規範逐步推演
 O = FunctionR.prototype = Function.prototype 
 L = FunctionL.__proto__ = Function.prototype 
 // 第一次判斷
 O == L 
 // 返回 true
3. Foo instanceof Foo
// 爲了方便表述,首先區分左側表達式和右側表達式
 FooL = Foo, FooR = Foo; 
 // 下面根據規範逐步推演
 O = FooR.prototype = Foo.prototype 
 L = FooL.__proto__ = Function.prototype 
 // 第一次判斷
 O != L 
 // 循環再次查找 L 是否還有 __proto__ 
 L = Function.prototype.__proto__ = Object.prototype 
 // 第二次判斷
 O != L 
 // 再次循環查找 L 是否還有 __proto__ 
 L = Object.prototype.__proto__ = null 
 // 第三次判斷
 L == null 
 // 返回 false
相關文章
相關標籤/搜索