这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战
typeof 语法
当我们想判断一个对象是基本数据类型还是引用数据类型,使用typeof可以准确的判断。
// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof(42) === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // Despite being "Not-A-Number"
typeof Number('1') === 'number'; // Number tries to parse things into numbers
typeof Number('shoe') === 'number'; // including values that cannot be type coerced to a number
typeof 42n === 'bigint';
// Strings
typeof '' === 'string';
typeof 'bla' === 'string';
typeof `template literal` === 'string';
typeof '1' === 'string'; // note that a number within a string is still typeof string
typeof (typeof 1) === 'string'; // typeof always returns a string
typeof String(1) === 'string'; // String converts anything into a string, safer than toString
// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(1) === 'boolean'; // Boolean() will convert values based on if they're truthy or falsy
typeof !!(1) === 'boolean'; // two calls of the ! (logical NOT) operator are equivalent to Boolean()
// Symbols
typeof Symbol() === 'symbol'
typeof Symbol('foo') === 'symbol'
typeof Symbol.iterator === 'symbol'
// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined';
// Objects
typeof {a: 1} === 'object';
// use Array.isArray or Object.prototype.toString.call
// to differentiate regular objects from arrays
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
typeof /regex/ === 'object'; // See Regular expressions section for historical results
// The following are confusing, dangerous, and wasteful. Avoid them.
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';
// Functions
typeof function() {} === 'function';
typeof class C {} === 'function';
typeof Math.sin === 'function';
复制代码
但是要注意:
当我们typeof null === 'object';
得到了object,这是一个我们不期望的结果。所以我们使用一个判断语句就可以准备的 对 如何判断一个数据是基本数据类型还是引用数据类型? 做出回答:
如何判断一个数据是基本数据类型还是引用数据类型?
const plainValues = ['number', 'string', 'boolean', 'bigint', 'symbol', 'undefined', 'null']
function isPlainValue(value) {
if (value === null) {
return true
}
return plainValues.includes(typeof value)
}
const flag = isPlainValue()
console.log(flag)
复制代码
如何判断该变量是否是一个函数
function c() {}
const d = () => {}
class Person {}
function* gen() {}
async function asf() {}
const fn = new Function()
console.log(typeof c)
console.log(typeof d)
console.log(typeof Person)
console.log(typeof gen)
console.log(typeof asf)
console.log(typeof fn)
复制代码
以上打印全都是function。
instanceof
P1 instanceof Person
instanceof 关键字是检测 p1对象的原型链上是否有Person构造函数的原型。一般用于自定义对象的判断。比如判断实例化对象是否属于某个构造函数。
实现一个instanceof
function instance(left,right){
left=left.__proto__
right=right.prototype
while(true){
if(left==null)
return false;
if(left===right)
return true;
left=left.__proto__
}
}
复制代码
当我们使用 const obj = Object.create(null)
创建一个对象时。obj instanceof Object
为false, 所以我们一般使用instanceof来判断自定义实例化对象。
如何判断一个数据是否是数组
Array.isArray(value)
Object.prototype.toString
Object.prototype.toString方法返回一个对象的字符表现串形式。
EcmaScript中定义的类型使用Object.prototype.toString可以精准的判断。
Object.prototype.toString.call(123) // [object Number]
Object.prototype.toString.call('str') // [object String]
Object.prototype.toString.call(true) // [object Boolean]
Object.prototype.toString.call(123n) // [object BigInt]
Object.prototype.toString.call(Symbol()) // [object Symbol]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call({}) // [object Object]
Object.prototype.toString.call([]) // [object Array]
Object.prototype.toString.call(Math) // [object Math]
Object.prototype.toString.call(JSON) // [object JSON]
Object.prototype.toString.call(new Function()) // [object Function]
Object.prototype.toString.call(new Date()) // [object Date]
Object.prototype.toString.call(new RegExp()) // [object RegExp]
Object.prototype.toString.call(new Error()) // [object Error]
复制代码
在上文中我们说到 如何判断该变量是否是一个函数
那么我们如何判断一个函数是什么类型的函数呢?
判断一个函数是什么类型的函数
那么如果我们想判断一个函数是async 标记的函数, 还是用generator标记的函数呢?也可以使用Object.prototype.toString。
Object.prototype.toString.call(async function () {}) // [object AsyncFunction]
Object.prototype.toString.call(function* () {}) // [object GeneratorFunction]
Object.prototype.toString.call(async function* () {}) // [object AsyncGeneratorFunction]
复制代码
怎么区分普通函数和箭头函数
const arrow_fn = () => {}
function fn() {}
console.log(arrow_fn.prototype) // undefined
console.log(fn.prototype) // {constructor: ƒ}
复制代码
但是这种方式也是不可靠的。
因为object可以通过定义一个Symbol来改变Object.prototype.toString()的行为。toStringTag属性,导致意外的结果。
const myDate = new Date();
Object.prototype.toString.call(myDate); // [object Date]
myDate[Symbol.toStringTag] = 'myDate';
Object.prototype.toString.call(myDate); // [object myDate]
Date.prototype[Symbol.toStringTag] = 'prototype polluted';
Object.prototype.toString.call(new Date()); // [object prototype polluted]
复制代码
所以为了保险起见,在判断一个对象时, 我们先判断下 obj[Symbol.toStringTag]
是否存在。然后在 Object.prototype.toString()进行判断。当然,如果这个对象是我们可控的,我们就不用判断啦。而且这个方法的精度更高。
总结: 我们判断类型都可以使用Object.prototype.toString进行判断,当使用自定义构造函数实例化对象时,我们使用instanceof来进行判断该对象的类型。