11

关于JS类型判断的思考

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzUxNjk4ODMzOA%3D%3D&%3Bmid=2247483760&%3Bidx=1&%3Bsn=307027a9c60398b48172192a05a09a68
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

初衷

写这篇文章的初衷是来源于 JS基础问题-类型判断 [1] ,仅当作巩固下知识。

我们常说学习一个知识点要学会延伸思考,点画线,线绘面,形成自己的知识体系。

一个小小的类型判断其实也可以拓展出很多知识点。

What: 什么是类型?

计算机程序的运行需要对值进行操作,而在编程语言中,能够表示并操作的值的类型称为数据类型。

编程语言最基本的特征就是支持多种数据类型。

Who:JS有哪几类数据类型,以及分别是什么?

JS有两类数据类型:原始类型(primitive type)和对象类型(object type)。

原始类型

number string boolean undefined null symbol Bigint [2]

指的注意的是null确实属于基本类型,因为有时它容易被误认为是对象类型。


typeof null === 'object' // 这应该算语言的一个bug

typeof null 感兴趣的可以看这个讨论 [3]

对象类型

object

实际上JS还有很多特殊的对象子类型,我们可以称之为复杂基本类型。

比如说:

String Number Boolean Function Array Date Regexp Error Object Buffer Map Set WeakSet WeakMap

这里又会有一个思考:基本数据类型与引用数据类型的区别,常见于函数的入参。

基本数据类型它是按值访问。


const a = 10;

let b = a;

b = 20;

QFVfMr2.png!web

引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址(“指针”)。通过这个引用地址可以快速查找到保存中堆内存中的对象。


const obj1 = new Object();


const obj2 = obj1;


obj2.name = "我有名字了";

aQBbUrE.jpg!web

Why:为什么我们需要自己实现JS类型判断?

因为JS自带的类型判断方法不能满足我们的需求。

JS自带的类型判断方法

typeof


console.log(typeof '11') // string

console.log(typeof 11) // number

console.log(typeof true) // boolean

console.log(typeof undefined) // undefined

console.log(typeof null) // object, 算语言的bug,实际上该方式并不能判断出null

console.log(typeof Symbol('test')) // symbol

console.log(typeof /.?/gi) // object

console.log(typeof []) // object

console.log(typeof new Date()) // object

y6BBZrN.jpg!web 你会发现typeof只能判断基本数据类型(null还是一个特例,需要特殊处理),不适用于判断对象类型,因为它无法判断出具体的子类型。

下面几个简单题目测试下是否掌握了typeof用法。


var y = 1, x = y = typeof x;

console.log(x) // undefined


var foo = {

bar: function() { return this.baz; },

baz: 1

};

(function(){

return typeof arguments[0]();//"undefined"

})(foo.bar);

instanceof

instanceof 主要的作用就是判断一个实例是否是其父类型或者祖先类型的实例。它是基于原型链的查找。


let person = function () {

}

let nicole = new person()

nicole instanceof person // true

我们看下面这个demo你就知道为什么有些场景下不能用instanceof来判断数据类型了。

const arr = []

const obj = {}

const func = function() {}


console.log(arr instanceof Array) // true

console.log(arr instanceof Object) // true

console.log(obj instanceof Object) // true

console.log(func instanceof Object) // true

How:如何实现JS类型判断?

下面我们看看lodash是如何进行JS类型判断的。

_.isObjectLike(value) 类对象


/**

* Checks if `value` is object-like. A value is object-like if it's not `null`

* and has a `typeof` result of "object".

*

* isObjectLike({})

* // => true

*

* isObjectLike([1, 2, 3])

* // => true

*

* isObjectLike(Function)

* // => false

*

* isObjectLike(null)

* // => false

*/

function isObjectLike(value) {

return typeof value === 'object' && value !== null

}


export default isObjectLike

_.isArguments(value) 类 arguments 对象


const toString = Object.prototype.toString


// Gets the `toStringTag` of `value`.

// 这个方法很重要

function getTag(value) {

if (value == null) {

return value === undefined ? '[object Undefined]' : '[object Null]'

}

return toString.call(value)

}


function isArguments(value) {

return isObjectLike(value) && getTag(value) == '[object Arguments]'

}

_.isArrayLike(value)


// 检查 value 是否为有效的类数组长度。

function isLength(value) {

return typeof value === 'number' &&

value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER

}



function isArrayLike(value) {

return value != null && typeof value !== 'function' && isLength(value.length)

}

_isBoolean()


// isBoolean(null) false

function isBoolean(value) {

return value === true || value === false ||

(isObjectLike(value) && getTag(value) == '[object Boolean]')

}

这里就不详细列举,感兴趣强烈推荐阅读 lodash源码 [4]

关于类型还涉及的知识点有

Primitive Types & Reference Types in JavaScript —— Bran van [5] JS值引用与值复制 [6] 动态类型语言与鸭子类型 [7] 你不知道的javascript中卷-强制类型转换 [8] JS类型的隐式转换 [9] JS中的相等性判断 [10]

References

[1] JS基础问题-类型判断:  https://elemefe.github.io/node-interview/#/sections/zh-cn/common?id=%e7%b1%bb%e5%9e%8b%e5%88%a4%e6%96%ad

[2] Bigint:  https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt

[3] typeof null 感兴趣的可以看这个讨论:  https://www.zhihu.com/question/66941121/answer/247939890

[4] lodash源码:  https://github.com/lodash/lodash

[5] Primitive Types & Reference Types in JavaScript —— Bran van:  https://link.zhihu.com/?target=https%3A//docstore.mik.ua/orelly/webprog/jscript/ch04_04.htm

[6] JS值引用与值复制:  https://link.zhihu.com/?target=https%3A//segmentfault.com/a/1190000015411195

[7] 动态类型语言与鸭子类型:  https://link.zhihu.com/?target=http%3A//book.51cto.com/art/201505/475153.htm

[8] 你不知道的javascript中卷-强制类型转换:  https://link.zhihu.com/?target=https%3A//www.jianshu.com/p/777a89b4ed9a

[9] JS类型的隐式转换:  https://link.zhihu.com/?target=https%3A//www.imooc.com/video/5675

[10] JS中的相等性判断:  https://link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/docs/Web/JavaScript/Equality_comparisons_and_sameness


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK