前言:本篇文章将介绍typeof、instanceof、以及Object.prototype.toString.call方法如何判断数据类型,以及实现了一个简单的instanceof和call函数。欢迎在评论区指正并且提出建议!
typeof
typeof可以判断基本数据类型,但是不能判断引用数据类型(对象)
console.log(typeof 2); // number
console.log(typeof true); // boolean
console.log(typeof 'str'); // string
console.log(typeof []); // object
console.log(typeof function(){}); // function
console.log(typeof {}); // object
console.log(typeof undefined); // undefined
console.log(typeof null); // object
instanceof
instanceof可以正确判断引用数据类型,原理是判断原型链上是否有右侧对象的原型。但是不能判断基本数据类型。
console.log(2 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
如果我们想让instanceof判断基本数据类型也是可以的!可以用包装类封装一层,如下。
被包裹的引用数据类型也能判断(毕竟会在原型链上找)
这里穿插一下instanceof的实现
function isObject(data) {
const type = typeof data;
// 注意,typeof null也是对象类型,所以先判断是否为null
return data && (type === "object" || type === "function");
}
function myIntance(left, right) {
//如果有一个不是
if (!isObject(left) || !isObject(right)) {
return false;
}
//取出右边对象的原型,进行判断
if (left.__proto__ === right.prototype) return true;
// 递归进行判断
return myIntance(left.__proto__, right);
}
console.log(myIntance([], Array)); //true
console.log(myIntance([], Object)); //true
console.log(myIntance({}, Object)); //true
console.log(myIntance(() => {}, Function)); //true
Object.prototype.toString.call
也可以使用Object原型上的toString方法,通过call修改this指向来调用该方法,进而判断数据类型。
因为很多包装类以及Function,Array等类型都是Object的实例,重写了Object的toString方法。所以我们需要调用最原始的toString来判断类型
const a = Object.prototype.toString;
console.log(a.call(2)); //[object Number]
console.log(a.call(true)); //[object Boolean]
console.log(a.call('str')); //[object String]
console.log(a.call([])); //[object Array]
console.log(a.call(function(){})); //[object Function]
console.log(a.call({})); //[object Object]
console.log(a.call(undefined)); //[object Undefined]
console.log(a.call(null)); //[object Null]
这里附上call方法的实现~
function myCall(thisArg, ...args) {
// 如果传入的是基本数据类型,就用包装类封装
thisArg = typeof thisArg === "object" ? thisArg : Object(thisArg);
// 获取this,也就是调用这个方法的函数
const fn = this;
// 使用隐式绑定,在thisArg上绑定fn并且调用,来改变this的指向
const symbolFn = Symbol("fn"); //用Symbol防止fn重名覆盖
thisArg[symbolFn] = fn;
// 调用函数,获取返回值
const res = thisArg[symbolFn](...args);
//删除Symbol属性
delete thisArg[symbolFn];
//返回
return res;
}
Function.prototype.call = myCall;
function foo(num1, num2) {
console.log(this);
console.log(this.name);
console.log(num1 + num2);
}
foo.call({ name: "wjj" }, 10, 20);