您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

javascript中判断数据类型的几种方式

2024/2/29 9:42:35发布45次查看
编写javascript代码的时候常常要判断变量,字面量的类型,可以用typeof,instanceof,array.isarray(),等方法,究竟哪一种最方便,最实用,最省心呢?本文探讨这个问题。
1. typeof
1.1 语法
typeof返回一个字符串,表示未经计算的操作数的类型。
语法:typeof(operand) | typeof operand
参数:一个表示对象或原始值的表达式,其类型将被返回
描述:typeof可能返回的值如下:
【相关课程推荐:javascript视频教程】  
类型 结果
undefined“undefined”null“object”boolean“boolean”number“number”bigint“bigint”string“string”symbol“symbol”
宿主对象(由js环境提供) 取决于具体实现
function对象 “function”
其他任何对象 “object”
从定义和描述上来看,这个语法可以判断出很多的数据类型,但是仔细观察,typeof null居然返回的是“object”,让人摸不着头脑,下面会具体介绍,先看看这个效果:
// 数值console.log(typeof 37) // numberconsole.log(typeof 3.14) // numberconsole.log(typeof(42)) // numberconsole.log(typeof math.ln2) // numberconsole.log(typeof infinity) // numberconsole.log(typeof nan) // number 尽管它是not-a-number的缩写,实际nan是数字计算得到的结果,或者将其他类型变量转化成数字失败的结果console.log(number(1)) //number number(1)构造函数会把参数解析成字面量console.log(typeof 42n) //bigint// 字符串console.log(typeof '') //stringconsole.log(typeof 'boo') // stringconsole.log(typeof `template literal`) // stringconsole.log(typeof '1') //string 内容为数字的字符串仍然是字符串console.log(typeof(typeof 1)) //string,typeof总是返回一个字符串console.log(typeof string(1)) //string string将任意值转换成字符串// 布尔值console.log(typeof true) // booleanconsole.log(typeof false) // booleanconsole.log(typeof boolean(1)) // boolean boolean会基于参数是真值还是虚值进行转换console.log(typeof !!(1)) // boolean 两次调用!!操作想短语boolean()// undefinedconsole.log(typeof undefined) // undefinedconsole.log(typeof declaredbutundefinedvariabl) // 未赋值的变量返回undefinedconsole.log(typeof undeclaredvariable ) // 未定义的变量返回undefined// 对象console.log(typeof {a: 1}) //objectconsole.log(typeof new date()) //objectconsole.log(typeof /s/) // 正则表达式返回object// 下面的例子令人迷惑,非常危险,没有用处,应避免使用,new操作符返回的实例都是对象console.log(typeof new boolean(true)) // objectconsole.log(typeof new number(1)) // objectconsole.log(typeof new string('abc')) // object// 函数console.log(typeof function () {}) // functionconsole.log(typeof class c { }) // functionconsole.log(typeof math.sin) // function
1.2 迷之null
javascript诞生以来,typeof null都是返回‘object’的,这个是因为javascript中的值由两部分组成,一部分是表示类型的标签,另一部分是表示实际的值。对象类型的值类型标签是0,不巧的是null表示空指针,它的类型标签也被设计成0,于是就有这个typeof null === ‘object’这个‘恶魔之子’。
曾经有ecmascript提案让typeof null返回‘null’,但是该提案被拒绝了。
1.3 使用new操作符
除function之外所有构造函数的类型都是‘object’,如下:
var str = new string('string'); var num = new number(100)console.log(typeof str) // objectconsole.log(typeof num) // objectvar func = new function()console.log(typeof func) // function
1.4 语法中的括号
typeof运算的优先级要高于“+”操作,但是低于圆括号
var idata = 99 console.log(typeof idata + ' wisen') // number wisen console.log(typeof (idata + 'wisen')) // string
1.5 判断正则表达式的兼容性问题
typeof /s/ === 'function'; // chrome 1-12 , 不符合 ecmascript 5.1typeof /s/ === 'object'; // firefox 5+ , 符合 ecmascript 5.1
1.6 错误
ecmascript 2015之前,typeof总能保证对任何所给的操作数都返回一个字符串,即使是没有声明,没有赋值的标示符,typeof也能返回undefined,也就是说使用typeof永远不会报错。
但是es6中加入了块级作用域以及let,const命令之后,在变量声明之前使用由let,const声明的变量都会抛出一个referenceerror错误,块级作用域变量在块的头部到声明变量之间是“暂时性死区”,在这期间访问变量会抛出错误。如下:
console.log(typeof undeclaredvariable) // 'undefined' console.log(typeof newletvariable) // referenceerror console.log(typeof newconstvariable) // referenceerror console.log(typeof newclass) // referenceerror let newletvariable const newconstvariable = 'hello' class newclass{}
1.7 例外
当前所有浏览器都暴露一个类型为undefined的非标准宿主对象document.all。typeof document.all === 'undefined'。景观规范允许为非标准的外来对象自定义类型标签,单要求这些类型标签与已有的不同,document.all的类型标签为undefined的例子在web领域被归类为对原ecma javascript标准的“故意侵犯”,可能就是浏览器的恶作剧。
总结:typeof返回变量或者值的类型标签,虽然对大部分类型都能返回正确结果,但是对null,构造函数实例,正则表达式这三种不太理想。
2. instanceof
2.1 语法
instanceof运算符用于检测实例对象(参数)的原型链上是否出现构造函数的prototype。
语法:object instanceof constructor
参数:object 某个实例对象
constructor 某个构造函数
描述:instanceof运算符用来检测constructor.property是否存在于参数object的原型链上。
// 定义构造函数 function c() { } function d() { } var o = new c() console.log(o instanceof c) //true,因为object.getprototypeof(0) === c.prototype console.log(o instanceof d) //false,d.prototype不在o的原型链上 console.log(o instanceof object) //true 同上 c.prototype = {} var o2 = new c() console.log(o2 instanceof c) // true console.log(o instanceof c) // false c.prototype指向了一个空对象,这个空对象不在o的原型链上 d.prototype = new c() // 继承 var o3 = new d() console.log(o3 instanceof d) // true console.log(o3 instanceof c) // true c.prototype现在在o3的原型链上
需要注意的是,如果表达式obj instanceof foo返回true,则并不意味着该表达式会永远返回true,应为foo.prototype属性的值可能被修改,修改之后的值可能不在obj的原型链上,这时表达式的值就是false了。另外一种情况,改变obj的原型链的情况,虽然在当前es规范中,只能读取对象的原型而不能修改它,但是借助非标准的__proto__伪属性,是可以修改的,比如执行obj.__proto__ = {}后,obj instanceof foo就返回false了。此外es6中object.setprototypeof(),reflect.setprototypeof()都可以修改对象的原型。
instanceof和多全局对象(多个iframe或多个window之间的交互)
浏览器中,javascript脚本可能需要在多个窗口之间交互。多个窗口意味着多个全局环境,不同全局环境拥有不同的全局对象,从而拥有不同的内置构造函数。这可能会引发一些问题。例如表达式[] instanceof window.frames[0].array会返回false,因为
array.prototype !== window.frames[0].array.prototype。
起初,这样可能没有意义,但是当在脚本中处理多个frame或多个window以及通过函数将对象从一个窗口传递到另一个窗口时,这就是一个非常有意义的话题。实际上,可以通过array.isarray(myobj)或者object.prototype.tostring.call(myobj) = "[object array]"来安全的检测传过来的对象是否是一个数组。
2.2 示例
string对象和date对象都属于object类型(它们都由object派生出来)。
但是,使用对象文字符号创建的对象在这里是一个例外,虽然原型未定义,但是instanceof of object返回true。
var simplestr = "this is a simple string"; var mystring = new string(); var newstr = new string("string created with constructor"); var mydate = new date(); var myobj = {}; var mynonobj = object.create(null); console.log(simplestr instanceof string); // 返回 false,虽然string.prototype在simplestr的原型链上,但是后者是字面量,不是对象 console.log(mystring instanceof string); // 返回 true console.log(newstr instanceof string); // 返回 true console.log(mystring instanceof object); // 返回 true console.log(myobj instanceof object); // 返回 true, 尽管原型没有定义 console.log(({}) instanceof object); // 返回 true, 同上 console.log(mynonobj instanceof object); // 返回 false, 一种创建非 object 实例的对象的方法 console.log(mystring instanceof date); //返回 false console.log( mydate instanceof date); // 返回 true console.log(mydate instanceof object); // 返回 true console.log(mydate instanceof string); // 返回 false
注意:instanceof运算符的左边必须是一个对象,像"string" instanceof string,true instanceof boolean这样的字面量都会返回false。
下面代码创建了一个类型car,以及该类型的对象实例mycar,instanceof运算符表明了这个myca对象既属于car类型,又属于object类型。
function car(make, model, year) { this.make = make; this.model = model; this.year = year;}var mycar = new car("honda", "accord", 1998);var a = mycar instanceof car; // 返回 truevar b = mycar instanceof object; // 返回 true
不是...的实例
要检测对象不是某个构造函数的实例时,可以使用!运算符,例如if(!(mycar instanceof car))
instanceof虽然能够判断出对象的类型,但是必须要求这个参数是一个对象,简单类型的变量,字面量就不行了,很显然,这在实际编码中也是不够实用。
总结:obj instanceof constructor虽然能判断出对象的原型链上是否有构造函数的原型,但是只能判断出对象类型变量,字面量是判断不出的。
3. object.prototype.tostring()
3.1. 语法
tostring()方法返回一个表示该对象的字符串。
语法:obj.tostring()
返回值:一个表示该对象的字符串
描述:每个对象都有一个tostring()方法,该对象被表示为一个文本字符串时,或一个对象以预期的字符串方式引用时自动调用。默认情况下,tostring()方法被每个object对象继承,如果此方法在自定义对象中未被覆盖,tostring()返回“[object type]”,其中type是对象的类型,看下面代码:
var o = new object(); console.log(o.tostring()); // returns [object object]
注意:如ecmascript 5和随后的errata中所定义,从javascript1.8.5开始,tostring()调用null返回[object, null],undefined返回[object undefined]
3.2. 示例
覆盖默认的tostring()方法
可以自定义一个方法,来覆盖默认的tostring()方法,该tostring()方法不能传入参数,并且必须返回一个字符串,自定义的tostring()方法可以是任何我们需要的值,但如果带有相关的信息,将变得非常有用。
下面代码中定义dog对象类型,并在构造函数原型上覆盖tostring()方法,返回一个有实际意义的字符串,描述当前dog的姓名,颜色,性别,饲养员等信息。
function dog(name,breed,color,sex) { this.name = name; this.breed = breed; this.color = color; this.sex = sex; } dog.prototype.tostring = function dogtostring() { return "dog " + this.name + " is a " + this.sex + " " + this.color + " " + this.breed } var thedog = new dog("gabby", "lab", "chocolate", "female"); console.log(thedog.tostring()) //dog gabby is a female chocolate lab
4. 使用tostring()检测数据类型
目前来看tostring()方法能够基本满足javascript数据类型的检测需求,可以通过tostring()来检测每个对象的类型。为了每个对象都能通过object.prototype.tostring()来检测,需要以function.prototype.call()或者function.prototype.apply()的形式来检测,传入要检测的对象或变量作为第一个参数,返回一个字符串"[object type]"。
// null undefined console.log(object.prototype.tostring.call(null)) //[object null] 很给力 console.log(object.prototype.tostring.call(undefined)) //[object undefined] 很给力 // number console.log(object.prototype.tostring.call(infinity)) //[object number] console.log(object.prototype.tostring.call(number.max_safe_integer)) //[object number] console.log(object.prototype.tostring.call(nan)) //[object number],nan一般是数字运算得到的结果,返回number还算可以接受 console.log(object.prototype.tostring.call(1)) //[object number] var n = 100 console.log(object.prototype.tostring.call(n)) //[object number] console.log(object.prototype.tostring.call(0)) // [object number] console.log(object.prototype.tostring.call(number(1))) //[object number] 很给力 console.log(object.prototype.tostring.call(new number(1))) //[object number] 很给力 console.log(object.prototype.tostring.call('1')) //[object string] console.log(object.prototype.tostring.call(new string('2'))) // [object string] // boolean console.log(object.prototype.tostring.call(true)) // [object boolean] console.log(object.prototype.tostring.call(new boolean(1))) //[object boolean] // array console.log(object.prototype.tostring.call(new array(1))) // [object array] console.log(object.prototype.tostring.call([])) // [object array] // object console.log(object.prototype.tostring.call(new object())) // [object object] function foo() {} let a = new foo() console.log(object.prototype.tostring.call(a)) // [object object] // function console.log(object.prototype.tostring.call(math.floor)) //[object function] console.log(object.prototype.tostring.call(foo)) //[object function] // symbol console.log(object.prototype.tostring.call(symbol('222'))) //[object symbol] // regexp console.log(object.prototype.tostring.call(/sss/)) //[object regexp]
上面的结果,除了nan返回number稍微有点差池之外其他的都返回了意料之中的结果,都能满足实际开发的需求,于是我们可以写一个通用的函数来检测变量,字面量的类型。如下:
let type = (function () { let type = {}; let typearr = ['string', 'object', 'number', 'array', 'undefined', 'function', 'null', 'symbol', 'boolean', 'regexp', 'bigint']; for (let i = 0; i < typearr.length; i++) { (function (name) { type['is' + name] = function (obj) { return object.prototype.tostring.call(obj) === '[object ' + name + ']' } })(typearr[i]) } return type })() let s = true console.log(type.isboolean(s)) // true console.log(type.isregexp(/22/)) // true
除了能检测ecmascript规定的八种数据类型(七种原始类型,boolean,null,undefined,number,bigint,string,symbol,一种复合类型object)之外,还能检测出正则表达式regexp,function这两种类型,基本上能满足开发中的判断数据类型需求。
5. 判断相等
既然说道这里,不妨说一说另一个开发中常见的问题,判断一个变量是否等于一个值。es5中比较两个值是否相等,可以使用相等运算符(==),严格相等运算符(===),但它们都有缺点,== 会将‘4’转换成4,后者nan不等于自身,以及+0 !=== -0。es6中提出”same-value equality“(同值相等)算法,用来解决这个问题。object.is就是部署这个算法的新方法,它用来比较两个值是否严格相等,与严格比较运算(===)行为基本一致。
console.log(5 == '5') // true console.log(nan == nan) // false console.log(+0 == -0) // true console.log({} == {}) // false console.log(5 === '5') // false console.log(nan === nan) // false console.log(+0 === -0) // true console.log({} === {}) // false
object.js()不同之处有两处,一是+0不等于-0,而是nan等于自身,如下:
let a = {} let b = {} let c = b console.log(a === b) // false console.log(b === c) // true console.log(object.is(b, c)) // true
注意两个空对象不能判断相等,除非是将一个对象赋值给另外一个变量,对象类型的变量是一个指针,比较的也是这个指针,而不是对象内部属性,对象原型等。
本文来自 js教程 栏目,欢迎学习!  
以上就是javascript中判断数据类型的几种方式的详细内容。
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product