JavaScript中typeof、toString、instanceof、constructor與in

JavaScript 是一種弱類型或者說動態語言。這意味着你不用提早聲明變量的類型,在程序運行過程當中,類型會被自動肯定。javascript

這也意味着你可使用同一個變量保存不一樣類型的數據。html

最新的 ECMAScript 標準定義了 7 種數據類型java

7種內置類型:Boolean、Null、Undefined、Number、String、Symbol (ECMAScript 6 新定義)和Object,除 Object 之外的全部類型都是不可變的(值自己沒法被改變)。linux

 

1、typeof

typeof操做符返回一個字符串,表示未經求值的操做數(unevaluated operand)的類型。查看在線代碼web

// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 儘管NaN是"Not-A-Number"的縮寫,意思是"不是一個數字"
typeof Number(1) === 'number'; // 不要這樣使用!

// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof返回的確定是一個字符串
typeof String("abc") === 'string'; // 不要這樣使用!

// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 不要這樣使用!

// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';

// Undefined
typeof undefined === 'undefined';
typeof blabla === 'undefined'; // 一個未定義的變量,或者一個定義了卻未賦初值的變量

// Objects
typeof {a:1} === 'object';
// 使用Array.isArray或者Object.prototype.toString.call方法能夠從基本的對象中區分出數組類型
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
// 下面的容易使人迷惑,不要這樣使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String("abc") === 'object';
// 從JavaScript一開始出現就是這樣的 
typeof null === 'object';
// 正則表達式
typeof /s/ === 'object'; // Chrome 12+ , 符合 ECMAScript 5.1 typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1 // 函數 typeof function(){} === 'function'; typeof Math.sin === 'function'; typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1

undefined(未賦值)和undeclared(未聲明)是有區別的。正則表達式

檢查全局變量的是否聲明的安全防範機制:數組

typeof DEBUG == "undefined"
//
window.DEBUG

 

2、toString

能夠經過使用toString.call(obj)來檢測對象類型。安全

能夠用來檢測ObjectNumberArrayDateFunctionStringBooleanErrorRegExpapp

下面的代碼與上面的代碼作了一一比較,其中在註釋中有標紅的「不一樣」,說明有區別。查看在線代碼ide

var toString = Object.prototype.toString;
// Numbers 都返回[object Number]
toString.call(37);
toString.call(3.14);
toString.call(Math.LN2);
toString.call(Infinity);
toString.call(Number(1));

// Strings 都返回[object String]
toString.call("");
toString.call("bla");
toString.call(String("abc"));

// Booleans 都返回[object Boolean]
toString.call(true);
toString.call(false);
toString.call(Boolean(true));

// Symbols 都返回[object Symbol]
toString.call(Symbol());
toString.call(Symbol('foo'));
toString.call(Symbol.iterator);

// Undefined 都返回[object Undefined]
toString.call(undefined);
//toString.call(blabla);//不一樣 一個未定義的變量會報錯

// Objects
toString.call({a:1});//[object Object]
toString.call([1, 2, 4]);//[object Array] 不一樣
toString.call(new Date());//[object Date] 不一樣
toString.call(new Boolean(true));//[object Boolean] 不一樣
toString.call(new Number(1));//[object Number] 不一樣
toString.call(new String("abc"));//[object String] 不一樣
toString.call(null);//[object Null] 不一樣
toString.call(/s/);//[object RegExp] 不一樣
toString.call(new TypeError());//[object Error] 不一樣

// 函數 都返回[object Function]
toString.call(function(){});
toString.call(Math.sin);

 

3、instanceof

instanceof 運算符能夠用來判斷某個構造函數的 prototype 屬性是否存在另一個要檢測對象的原型鏈上,返回boolean值。語法以下:

也就比對object.__proto__與constructor.prototype是否對應。

JavaScript instanceof 運算符代碼,參考自《JavaScript instanceof 運算符深刻剖析

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)// 這裏重點:當 O 嚴格等於 L 時,返回 true 
      return true; 
    L = L.__proto__; 
  } 
 }

object:要檢測的對象,constructor:某個構造函數。查看在線代碼

 1 // 定義構造函數
 2 function C(){} 
 3 function D(){} 
 4 
 5 var o = new C();
 6 o instanceof C; // true,由於 Object.getPrototypeOf(o) === C.prototype
 7 //o.__proto__={}; //改變o原型鏈,o instanceof C將會返回false
 8 o instanceof D; // false,由於 D.prototype不在o的原型鏈上
 9 o instanceof Object; // true,由於Object.prototype.isPrototypeOf(o)返回true
10 C.prototype instanceof Object // true,同上
11 
12 C.prototype = {};
13 var o2 = new C();
14 o2 instanceof C; // true
15 o instanceof C; // false,C.prototype指向了一個空對象,這個空對象不在o的原型鏈上.
16 
17 D.prototype = new C(); // 繼承
18 var o3 = new D();
19 o3 instanceof D; // true
20 o3 instanceof C; // true

有兩種方式能夠將"o instanceof C"返回「false」:

一、注意上面代碼的第12行,改變了函數C.prototype屬性,改變以後致使這個對象不在o的原型鏈上。

二、改變對象o的原型鏈,藉助於非標準的__proto__魔法屬性能夠實現。好比代碼的第7行執行o.__proto__ = {}。

 

這裏須要注意一個地方,就是Object.prototype.isPrototypeOf()與instanceof的區別。請看下面的代碼

var human = function() {}
var socrates = Object.create(human);
console.log(human.isPrototypeOf(socrates)); // true
console.log(socrates instanceof human); // false
console.log(socrates.__proto__ == human.prototype);//false
console.log(socrates.__proto__ == human);//true

上面的Object.create()傳遞的是human函數,「socrates.__proto__ == human.prototype」不相等,

也就是說human.prototype不在socrates的原型鏈上,因此instanceof返回的是false。

isPrototypeOf() 是指測試一個對象是否存在於另外一個對象的原型鏈上;如今human這個對象在socrates的原型鏈上。

 

4、constructor

constructor返回一個指向建立了該對象原型的函數引用。

須要注意的是,該屬性的值是那個函數自己,而不是一個包含函數名稱的字符串。對於原始值(如1,true 或 "test"),該屬性爲只讀。

全部對象都會從它的原型上繼承一個 constructor 屬性。查看在線代碼

一、在JavaScript的繼承中,instanceof和constructor表現的是不同的:

function C(){} 
function D(){} 
D.prototype = new C(); // 繼承
var o = new D();
o instanceof D; // true
o instanceof C; // true
o.constructor == D; // false
o.constructor == C; // true
o.constructor == D.prototype.constructor;//true
o.constructor == Object.prototype.constructor;// false

對象的constructor屬性是根據函數的prototype.constructor來的。

 

二、改變這個對象的constructor屬性的值,只有 true, 1"test" 的不受影響,其餘的都變成了"function type(){}"

function Type() { };
var    types = [
    new Array,
    [],
    new Boolean,
    true,        // remains unchanged
    new Date,
    new Error,
    new Function,
    function(){},
    Math,    
    new Number,
    1,           // remains unchanged
    new Object,
    {},
    new RegExp,
    /(?:)/,
    new String,
    "test"       // remains unchanged
];
for(var i = 0; i < types.length; i++) {
    types[i].constructor = Type;
    types[i] = [ types[i].constructor, types[i] instanceof Type, types[i].toString() ];
    console.log(types[i]);
};

下圖分別是「new Boolean」 和 「true」的打印結果:

 

5、in

in操做,若是指定的屬性在指定的對象中會返回true,語法以下:

1)與hasOwnProperty比較

hasOwnProperty() 方法用來判斷某個對象是否含有指定的自身屬性。

多了個自身。個人理解就是原型鏈上的公共屬性,判斷的時候會返回false。下面全部的代碼均可以在線查看到

function colour() {
  this.a = 1;
}
colour.prototype.b = function() {
  return 2;
}
var mine = new colour();
console.log("a" in mine);//true
console.log("b" in mine);//true
console.log(mine.hasOwnProperty("a"));//true
console.log(mine.hasOwnProperty("b"));//false

 

2)用in判斷對象屬性

in判斷的是數組或對象的key屬性。數組是一類特殊的對象,數組具備length屬性,而對象沒有。可參考《對象和數組 (JavaScript)

var arr = ["a","b","c"];
console.log(0 in arr);//true
console.log(3 in arr);//false
var ob = {0:"a", 1:"b", 2:"c"};
console.log(0 in ob);//true
console.log(3 in ob);//false

上面的代碼中數組的key是「0,1,2」與對象的key是同樣的。

 

3)(delete)刪除對象的屬性

在使用delete後,屬性判斷都變成了「false」。

var arr = ["a","b","c"];
delete arr[0];
console.log(0 in arr);//false
var ob = {0:"a", 1:"b", 2:"c"};
delete ob[0];
console.log(0 in ob);//false

 

4)for...in循環

這裏用上面示例中的對象mine。

for(property in mine) {
  console.log(property);
}

將會把上面的一個私有和公有的屬性打印出來。這裏注意,若是我在對象的公共父級(例如Object)中加個屬性,也是會打印出來的。

Object.prototype.z = function() {
};

 

5)巧用in操做

if (value == "a" || value == "b" || value == "c") {
     //....
}
//替換爲
if (value in {"a":"", "b":"", "c":""}) {
    //....
}

 

 

參考資料:

http://www.cnblogs.com/ecalf/archive/2012/12/03/2799968.html   JavaScript對象及原型繼承有關的屬性

http://anykoro.sinaapp.com/2012/01/31/javascript%E4%B8%ADfunctionobjectprototypes__proto__%E7%AD%89%E6%A6%82%E5%BF%B5%E8%AF%A6%E8%A7%A3/    Javascript中Function,Object,Prototypes,__proto__等概念詳解

http://rockyuse.iteye.com/blog/1426510   理解js中的原型鏈,prototype與__proto__的關係

http://www.cnblogs.com/snandy/archive/2012/09/01/2664134.html   JavaScript中__proto__與prototype的關係

http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html   Javascript繼承機制的設計思想

http://www.linuxfly.org/post/524/     JavaScript 的in 操做符

相關文章
相關標籤/搜索