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不是构造器。


typeofinstanceof
作用检测数据类型检测对象之间的关联性
返回小写字母字符串布尔值
操作数简单数据类型、函数或者对象左边必须是引用类型,右边必须是函数
操作数个数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));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值