JavaScript中的数据类型检测原理

JavaScript中的数据类型检测原理

专题汇总-数据类型检测

  • typeof
  • instanceof & constructor
  • Object.prototype.toString.call([value])
  • 封装一个数据类型检测的方法库

typeof

/*
typeof:用来检测数据类型的运算符
    typeof [value]
@return
    首先是个字符串
    字符串中包含对应的数据类型,例如:"number","string","object","boolean","undefeined","symbol","function"
@局限性
    不能具体区分对象数据类型的值
    typeof null     //"object"
    typeof []       //"object"
    typeof {}       //"object"
    typeof /^$/     //"object"
@优势
    使用方便,所以在真实项目中,我们也会大量应用它来检测,尤其是在检测基本类型值(除null之外)和函数类型值的时候,它还是很方便的
*/
function func(n,m,callback){
    //=>ES6:func(n=0,m=0)
    //=>检测形参的值是否为undefined
    n === "undefined"? n=0 : null;
    typeof m ==="undefined" ? m=0 : null;
    //=>基于逻辑或逻辑与处理(瑕疵:不仅仅是不传赋值默认值,如果传递的值是假也会处理成默认值)
    //n = n || 0;
    //m = m || 0;
    
    /*回调函数执行*/
    typeof callback ==="function" ? callback() : null;
}
typeof undefined;   //"undefined"

typeof true;        //"boolean"
typeof false;       //"boolean"

typeof 6;           //"number"
typeof 6.5;         //"number"
typeof NaN;         //"number"

typeof "LBJhui";        //"string"
typeof 'LBJhui';        //"string"

hello = function(){};
typeof hello;               //"function"

typeof Symbol;              //"function"
typeof new Function();      //"function"

typeof [];                  //"object"
typeof {};                  //"object"
typeof null;                //"object"
typeof new Array();         //"object"
typeof new Object();        //"object"
typeof new Error();         //"object"
typeof new Number();        //"object"
typeof new String();        //"object"
typeof new Date();          //"object"
typeof new RegExp();        //"object"

返回一个小写字母的类型字符串

只需要一个操作数

简单数据类型或者函数或者对象

在 ECMAScript 2015 之前,typeof 总能保证对任何所给的操作数返回一个字符串。即便是没有声明的标识符,typeof 也能返回 'undefined'。使用 typeof 永远不会抛出错误。

但在加入了块级作用域的 let 和 const 之后,在其被声明之前对块中的 letconst 变量使用 typeof 会抛出一个 ReferenceError。块作用域变量在块的头部处于“暂存死区”,直至其被初始化,在这期间,访问变量将会引发错误。

typeof undeclaredVariable === 'undefined';
typeof newLetVariable; // ReferenceError
typeof newConstVariable; // ReferenceError
typeof newClass; // ReferenceError

let newLetVariable;
const newConstVariable = 'hello';
class newClass{};

instanceof & constructor

/*
instanceof:本意是用来检测实例是否隶属于某个类的运算符,我们基于这样的方式,也可以用来做某些数据类型的检测,例如:数组、正则等
@局限性
    不能处理基本数据类型
    只要在当前实例的原型链(__proto__)中出现过的类,检测结果都是true(用户可能会手动修改原型链的指向:example.__proto__ 或者 在类的继承中 等情况)
*/
let arr[],
    reg = /^$/,
    obj = {};
arr instanceof Array;       //true
reg instanceof Array;       //false
arr instanceof Object;      //true
obj instanceof Array;       //false

1 instanceof Number;        //false
//创建值的两种方式(不管哪种方式都是所属于类的实例)
//字面量:let n = 12;
//构造函数:let m = new Number("12")

function func(){
    argument instanceof Array;      //false
    
    argument.__proto__ = Array.prototype
    argument instanceof Array;      //true
}


/*
constructor:构造函数
@原理:在类的原型上一般都会带有constructor属性,存储当前类本身,我们也是利用这一点,获取某类的实例constructor属性值,验证是否为所属的类,从而进行数据类型检测
@局限性:constructor属性值太容易被修改了
*/
let n = 12;
let arr = [];
n.constructor;          //ƒ Number() { [native code] }
n.constructor === Number;       //true
arr.constructor === Array;      //true
arr.constructor === Object;     //false
arr.constructor = 111;//设置私有属性
arr.constructor === Array;      //false
Func.prototype = {};        //这样原型上没有constructor属性(重构了)
a = new Number(888);
a instanceof Number;        //true

b = new String('LBJhui');
b instanceof String;        //true

c = new Array(6,66,666);
c instanceof Array;         //true

d = new Object();
d instanceof Object;        //true

"LBJhui" instanceof String;     //false
888 instanceof Number;          //false
true instanceof Boolean;        //false

[1,2] instanceof Array;         //true

var person = {name:"LBJhui",gender:"male"};
person instanceof Object;       //true

new Number(888) instanceof Number;      //true

以上结果显示,直接的字面量值判断数据类型,只有引用数据类型(Array,Function,Object)被精准判断,其他(Number,Boolean,String)字面值不能被instanceof精准判断。

需要注意的是,如果表达式 obj instanceof Foo 返回 true,则并不意味着该表达式会永远返回 true,因为 Foo.prototype 属性的值有可能会改变,改变之后的值很有可能不存在于 obj 的原型链上,这时原表达式的值就会成为 false。另外一种情况下,原表达式的值也会改变,就是改变对象 obj 的原型链的情况,虽然在目前的ES规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的 __proto__ 伪属性,是可以实现的。比如执行 obj.__proto__ = {} 之后,obj instanceof Foo 就会返回 false 了。

instanceof来判断null和undefined,浏览器在这里报错了,它认为null,undefined不是构造器。


... typeof instanceof
作用 检测数据类型 检测对象之间的关联性
返回 小写字母字符串 布尔值
操作数 简单数据类型、函数或者对象 左边必须是引用类型,右边必须是函数
操作数个数 1个 2个

Object.prototype.toString.call([value])

/*
Object.prototype.toString.call([value]):调用Object原型上的toString方法,让方法执行的时候,方法中的this是要检测的数据类型,从而获取到数据类型所属类的详细信息
toString() 方法返回一个表示该对象的字符串。
@信息的模板
    "[object 所属类]",例如:"[object Array]"
在所有的数据类型类中,它们的原型上都有toString方法,除Object.prototype.toString不是把数据值转换为字符串,其余的都是转换为字符串,而Object原型上的toString是检测当前实例隶属类的详细信息的(检测数据类型)
    obj.toString()
    1.首先基于原型链查找机制,找到Object.prototype.toString
    2.把找到的方法执行,方法中的this->obj
    3.方法内部把this(obj)的所属类信息输出
    =>方法执行,方法中的this是谁,就是检测谁的所属类信息
这个方法很强大, 所有数据类型隶属于的类信息检测的一清二楚
Number/String/Boolean/Null/Undefined/Symbol/Object/Array/RegExp/Data/Math/Function...
*/
[12,23].toString();     //"12,23"
/^\d+$/.toString();     //"/^\d+$/"
(function anonymous(){}).toString();        //"function anonymous(){}"

let obj1 = {},
    obj2 = {
    name:"LBJhui"
    }
obj1.toString();        //"[object Object]"
obj2.toString();        //"[object Object]"

let obj = {};
obj.toString.call(100)                  //"[object Number]"
Object.prototype.toString.call(100)     //"[object Number]"

let _obj ={};
toString = _obj.toString;
toString.call();

每个对象都有一个 toString() 方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString() 方法被每个 Object 对象继承。如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中 type 是对象的类型。以下代码说明了这一点:

var o = new Object();
o.toString(); // returns [object Object]

可以通过 toString() 来获取每个对象的类型。为了每个对象都能通过 Object.prototype.toString() 来检测,需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,传递要检查的对象作为第一个参数,称为 thisArg

var toString = Object.prototype.toString;
toString.call(333);          // [object Number]
toString.call("aaa");        // [object String]
toString.call(true);         // [object Boolean]
toString.call([]);           // [object Array]
toString.call(function(){}); // [object Function]
toString.call({});           // [object Object]
toString.call(undefined);    // [object Undefined]
toString.call(null);         // [object Null]

// 甚至于js的内置对象也能被精确判断
toString.call(new Date);     // [object Date]
toString.call(new String);   // [object String]
toString.call(Math);         // [object Math]

封装一个数据类型检测的方法库

let _obj = {
    isNumeric:"Number",
    isBoolean:"Boolean",
    isString:"String",
    isNull:"Null",
    isUndefined:"Undefined",
    isSymbol:"Symbol",
    isPlainObject:"Object",
    isArray:"Array",
    isRegExp:"RegExp",
    isDate:"Date",
    isFunction:"Function",
    isWindow:"Window"
},
_toString.call(val) = _obj.toString;
_type = {};
for(let key in _obj){
    if(!_obj.hasOwnProperty(key)) break;
    //key =isNumeric
    //_obj[key]="Number"
    //val=12
    let reg = new RegExp("\\[Object" + _obj[key] + "\\]");
    _type[key] = function anonymous(val){
        return reg.test(_toString.call(val));
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341