如何判斷 ECMAScript 的變數型別 ?
栏目: JavaScript · 发布时间: 5年前
内容简介:ECMAScript 雖然是 Dynamic Language,但並不代表 Variable 沒有 Type,只是其內建獲得 Type 的方式包含太多VS Code 1.33.0Quokka 1.0.205
ECMAScript 雖然是 Dynamic Language,但並不代表 Variable 沒有 Type,只是其內建獲得 Type 的方式包含太多 驚喜
,成為備受爭議的部分。本文整理出 4 種獲得 Type 方式,各有其優缺點,最後整理出自己的 typeof()
,可以判斷出各種 Type。
Version
VS Code 1.33.0
Quokka 1.0.205
ECMAScript 5
Ramda 0.26.1
Type
本文將介紹 5 種獲得 Type 方法:
typeof instanceof Object.prototype.toString() is() typeof()
Number
Number 共有 3 種建立方法:
- Number literal
- Number function
- Number constructor
實務上最常使用的是的 number literal,轉型時會使用 number function (或使用 +
operator),但 number constructor 實務上不建議使用。
import { is } from 'ramda'; /** typeof */ console.log(typeof 1); console.log(typeof Number(1)); console.log(typeof new Number(1)); /** instanceof */ console.log(1 instanceof Number); console.log(Number(1) instanceof Number); console.log(new Number(1) instanceof Number); /** Object.prototype.toString() */ console.log(Object.prototype.toString.call(1)); console.log(Object.prototype.toString.call(Number(1))); console.log(Object.prototype.toString.call(new Number(1))); /** is() */ console.log(is(Number, 1)); console.log(is(Number, Number(1))); console.log(is(Number, new Number(1)));
typeof
number object
instanceof
false true
instanceof
的邏輯理論上沒錯,但使得 typeof
與 instanceof
都有其不足,無法同時判斷 literal、function 與 constructor 所建立的 number,實務上並不好用
Object.prototype.toString()
- 無論對於 literal、function、constructor 所產生的 number,都回傳
number
Ramda 之 is()
- 無論對於 literal、function、constructor 所產生的 number,都回傳
true
Object.prototype.toString()
與 is()
都能同時判斷 literal、function 與 constructor 所產生的 number,實務上比較好用
String
String 共有 3 種建立方法:
- String literal
- String function
- String constructor
實務上最常使用的是的 string literal,轉型時會使用 string function (或使用 + ''
operator),但 string constructor 實務上不建議使用。
import { is } from 'ramda'; /** typeof */ console.log(typeof 'abc'); console.log(typeof String('abc')); console.log(typeof new String('abc')); /** instanceof */ console.log('abc' instanceof String); console.log(String('abc') instanceof String); console.log(new String('abc') instanceof String); /** Object.prototype.toString() */ console.log(Object.prototype.toString.call('abc')); console.log(Object.prototype.toString.call(String('abc'))); console.log(Object.prototype.toString.call(new String('abc'))); /** is() */ console.log(is(String, 'abc')); console.log(is(String, String('abc'))); console.log(is(String, new String('abc')));
typeof
string object
instanceof
false true
instanceof
的邏輯理論上沒錯,但使得 typeof
與 instanceof
都有其不足,無法同時判斷 literal、function 與 constructor 所建立的 string,實務上並不好用
Object.prototype.toString()
- 無論對於 literal、function、constructor 所產生的 string,都回傳
string
Ramda 之 is()
- 無論對於 literal、function、constructor 所產生的 string,都回傳
true
Object.prototype.toString()
與 is()
都能同時判斷 literal、function 與 constructor 所產生的 string,實務上比較好用
Boolean
Boolean 共有 3 種建立方法:
- Boolean literal
- Boolean function
- Boolean constructor
實務上最常使用的是的 boolean literal,轉型時會使用 boolean function (或使用 !!
operator,且 ECMAScript 支援 boolean coercion,會自動轉型),但 boolean constructor 實務上不建議使用。
import { is } from 'ramda'; console.log(typeof true); console.log(typeof Boolean(true)); console.log(typeof new Boolean(true)); console.log(true instanceof Boolean); console.log(Boolean(true) instanceof Boolean); console.log(new Boolean(true) instanceof Boolean); console.log(Object.prototype.toString.call(true)); console.log(Object.prototype.toString.call(Boolean(true))); console.log(Object.prototype.toString.call(new Boolean(true))); console.log(is(Boolean, true)); console.log(is(Boolean, Boolean(true))); console.log(is(Boolean, new Boolean(true)));
typeof
boolean object
instanceof
false true
instanceof
的邏輯理論上沒錯,但使得 typeof
與 instanceof
都有其不足,無法同時判斷 literal、function 與 constructor 所建立的 boolean,實務上並不好用
Object.prototype.toString()
- 無論對於 literal、function、constructor 所產生的 boolen,都回傳
boolean
Ramda 之 is()
- 無論對於 literal、function、constructor 所產生的 boolean,都回傳
true
Object.prototype.toString()
與 is()
都能同時判斷 literal、function 與 constructor 所產生的 boolean,實務上比較好用
Undefined
undefined
在 ECMAScript 已獨立成一個 type,其值也是 undefined
。
import { isNil } from 'ramda'; /** typeof */ console.log(typeof undefined); /** instanceof */ // N/A /** Object.prototype.toString() */ console.log(Object.prototype.toString.call(undefined)); /** isNil() */ console.log(isNil(undefined));
typeof
- 判斷
undefined
會如預期回傳undefined
instanceof
- 無法判斷
undefined
,因為不存在 undefined constructor
Object.prototype.toString()
- 判斷
undefined
會如預期回傳undefined
isNil()
-
is()
無法判斷undefined
,要改用isNil()
,如預期回傳true
Ramda 使用 isNil()
使得 type 判斷分裂成兩個 function,實務上沒那麼好用,目前只有 Object.prototype.toString()
能達到單一 function 判斷所有 type
Null
null
在 ECMAScript 已獨立成一個 type,其值也是 null
。
import { isNil } from 'ramda'; /** typeof */ console.log(typeof null); /** instanceof */ // N/A /** Object.prototype.toString() */ console.log(Object.prototype.toString.call(null)); /** isNil() */ console.log(isNil(null));
typeof
- 判斷
null
會如預期回傳object
,這是已知的 bug,但因為歷史因素,無法修改,變成 feature
instanceof
- 無法判斷
null
,因為不存在 null constructor
Object.prototype.toString()
- 判斷
null
會如預期回傳null
isNil()
-
is()
無法判斷null
,要改用isNil()
,如預期回傳true
Ramda 使用 isNil()
使得 type 判斷分裂成兩個 function,實務上沒那麼好用,目前只有 Object.prototype.toString()
能達到單一 function 判斷所有 type
Object
Object 共有 5 種建立方法:
- Object literal
- Object constructor
- Constructor function
- Class
- Object.create()
實務上最常使用的是的 object literal,而 constructor function、class 與 Object.create()
都有其適用時機,但 object constructor 實務上不建議使用。
/** object literal */ console.log(typeof {}); /** object constructor */ console.log(typeof new Object()); /** constructor function */ function Foo1() {} console.log(typeof new Foo1()); /** class */ class Foo2 {} console.log(typeof new Foo2()); /** Object.create() */ console.log(typeof Object.create({}));
typeof
- 無論使用哪一種方式建立 object,都會如預期回傳
object
/** object literal */ console.log({} instanceof Object); /** object constructor */ console.log(new Object() instanceof Object); /** constructor function */ function Foo1() {} console.log(new Foo1() instanceof Object); /** class */ class Foo2 {} console.log(new Foo2() instanceof Object); /** Object.create() */ console.log(Object.create({}) instanceof Object);
instanceof
- 無論使用哪一種方式建立 object,都會如預期回傳
true
/** object literal */ console.log(Object.prototype.toString.call({})); /** object constructor */ console.log(Object.prototype.toString.call(new Object())); /** constructor function */ function Foo1() {} console.log(Object.prototype.toString.call(new Foo1())); /** class */ class Foo2 {} console.log(Object.prototype.toString.call(new Foo2())); /** Object.create() */ console.log(Object.prototype.toString.call(Object.create({})));
Object.prototype.toString()
- 無論使用哪一種方式建立 object,都會如預期回傳
object
import { is } from 'ramda'; /** object literal */ console.log(is(Object, {})); /** object constructor */ console.log(is(Object, new Object())); /** constructor function */ function Foo1() {} console.log(is(Object, new Foo1())); /** class */ class Foo2 {} console.log(is(Object, new Foo2())); /** Object.create() */ console.log(is(Object, Object.create({})));
is()
- 無論使用哪一種方式建立 object,都會如預期回傳
true
對於 object,無論使用 typeof
、 instanceof
、 Object.prototype.toString()
或 is()
,都可以如預期判斷出 object
Array
Array 共有 3 種建立方法:
- Array literal
- Array function
- Array constructor
實務上最常使用的是的 array literal,建立 empty array 時會使用 array function,但 array constructor 實務上不建議使用 (因為效果與 array function 一樣)。
import { is } from 'ramda'; /** typeof */ console.log(typeof []); console.log(typeof Array(0)); console.log(typeof new Array(0)); /** instanceof */ console.log([] instanceof Array); console.log(Array(0) instanceof Array); console.log(new Array(0) instanceof Array); /** Object.prototype.toString() */ console.log(Object.prototype.toString.call([])); console.log(Object.prototype.toString.call(Array(0))); console.log(Object.prototype.toString.call(new Array(0))); /** is() */ console.log(is(Array, [])); console.log(is(Array, Array(0))); console.log(is(Array, new Array(0)));
typeof
- 無論使用哪一種方式建立 array,都無法如預期回傳
array
,而是回傳object
,這是比較困擾的地方
instanceof
- 無論使用哪一種方式建立 object,都會如預期回傳
true
Object.prototype.toString()
- 無論對於 literal、function、constructor 所產生的 array,都回傳
array
Ramda 之 is()
- 無論對於 literal、function、constructor 所產生的 array,都回傳
true
instanceof
、 Object.prototype.toString()
與 is()
都能同時判斷 literal、function 與 constructor 所產生的 array,實務上比較好用,但 typeof
則完全誤判為 object
Function
Function 共有 4 種建立方法:
- Function declaration
- Function expression
- Function constructor
- Arrow function
實務上最常使用的是的 function expression 與 arrow function,function declaration 則漸漸較少使用,但 function constructor 使用機會更少,除非想在 run-time 動態湊出 function。
/** function declaration */ function fun() {} console.log(typeof fun); /** function expression */ console.log(typeof function() {}); /** function constructor */ console.log(typeof new Function()); /** arrow function */ console.log(typeof (() => {}));
typeof
- 無論使用哪一種方式建立 function,都會如預期回傳
function
/** function declaration */ function fun() {} console.log(fun instanceof Function); /** function expression */ console.log(function() {} instanceof Function); /** function constructor */ console.log(new Function() instanceof Function); /** arrow function */ console.log((() => {}) instanceof Function);
instanceof
- 無論使用哪一種方式建立 function,都會如預期回傳
true
/** function declaration */ function fun() {} console.log(Object.prototype.toString.call(fun)); /** function expression */ console.log(Object.prototype.toString.call(function() {})); /** function constructor */ console.log(Object.prototype.toString.call(new Function())); /** arrow function */ console.log(Object.prototype.toString.call(() => {}));
Object.prototype.toString()
- 無論使用哪一種方式建立 function,都會如預期回傳
function
import { is } from 'ramda'; /** function declaration */ function fun() {} console.log(is(Function, fun)); /** function expression */ console.log(is(Function, function() {})); /** function constructor */ console.log(is(Function, new Function())); /** arrow function */ console.log(is(Function, () => {}));
is()
- 無論使用哪一種方式建立 object,都會如預期回傳
true
對於 function,無論使用 typeof
、 instanceof
、 Object.prototype.toString()
或 is()
,都可以如預期判斷出 function
typeof()
let typeof = data => Object.prototype.toString.call(data).slice(8, -1).toLowerCase(); console.log(typeof(1)); console.log(typeof(new Number(1))); console.log(typeof(new String('abc'))); console.log(typeof(new String('abc'))); console.log(typeof(true)); console.log(typeof(new Boolean(true))); console.log(undefined); console.log(null); console.log(typeof({})); console.log(typeof([])); console.log(typeof(()=>{}));
根據以上經驗,我們發現只有一種方式能抓到所有 type 都正確,那就是 Object.prototype.toString()
,但其回傳還包含 [Object ]
等不需要部分,且 type 是第一個字大寫,因此只要稍作加工,就可以與 typeof
完全一樣。
let typeof = data => Object.prototype.toString.call(data).slice(8, -1).toLowerCase();
一樣使用 Object.prototype.toString()
,利用 slice()
抓到我們要的部分,最後再 toLowerCase()
轉成全小寫。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript设计模式与开发实践
曾探 / 人民邮电出版社 / 2015-5 / 59.00元
本书在尊重《设计模式》原意的同时,针对JavaScript语言特性全面介绍了更适合JavaScript程序员的了16个常用的设计模式,讲解了JavaScript面向对象和函数式编程方面的基础知识,介绍了面向对象的设计原则及其在设计模式中的体现,还分享了面向对象编程技巧和日常开发中的代码重构。本书将教会你如何把经典的设计模式应用到JavaScript语言中,编写出优美高效、结构化和可维护的代码。一起来看看 《JavaScript设计模式与开发实践》 这本书的介绍吧!