JavaScript中typeof
一. typeof操作符
typeof
操作符用于返回正在使用值的类型。
// 使用原始值let mNull = null;let mUndefined = undefined;let mString = 'mazey';let mNumber = 123;let mBoolean = true;let mFunction = function () { return true;};// 用构造函数的方式new一个实例let oString = new String('cherrie');let oRegExp = new RegExp('^[0-9]+$');let oFunction = new Function('x', 'y', 'return x + y');let oObj = {};let oNew = new Object();// typeof值console.log(typeof mNull); // objectconsole.log(typeof mUndefined); // undefinedconsole.log(typeof mString); // stringconsole.log(typeof mNumber); // numberconsole.log(typeof mBoolean); // booleanconsole.log(typeof mFunction); // functionconsole.log(typeof oString); // objectconsole.log(typeof oRegExp); // objectconsole.log(typeof oFunction); // functionconsole.log(typeof oObj); // objectconsole.log(typeof oNew); // object
在《JavaScript启示录》中new RegExp()
介绍会返回function
,但是事实上我在chrome控制台中看到的是object
。
于是我console.log(new RegExp('^[0-9]+$'))
,打印出来的是字符串/^[0-9]+$/
。
console.log(new RegExp('^[0-9]+$')); // /^[0-9]+$/console.log(RegExp); // ƒ RegExp() { [native code] } 原始值console.log(String); // ƒ String() { [native code] } 原始值console.log(/^[0-9]+$/); // /^[0-9]+$/console.log(new RegExp('^[0-9]+$') === /^[0-9]+$/); // falseconsole.log(RegExp('^[0-9]+$') === /^[0-9]+$/); // false
综上可以看出现版本RegExp
和String Number
一样属于JavaScript的原始值。
Math
作为JavaScript中的静态对象回返回什么呢?
console.log(typeof Math); // objectconsole.log(typeof Math.PI); // numberconsole.log(typeof Math.ceil); // function
所以Math
的__proto__
还是Object
,typeof
还能返回对象的属性和方法的类型。
typeof使用场景
1.判断某个变量是否已定义
console.log(typeof aaa); // 'undefined'// 判断if (typeof bbb === 'undefined') { console.log('变量未定义');}
2.区分原始值和复杂值(对象值)
因为复杂值往往返回object
,当然有个例外就是原始值里面的null
也返回object
,然后function
作为Object
的实例也是复杂值。
// 判断是否时复杂值(对象值)function isObject (m) { return (typeof m === 'function' || (typeof m === 'object' && m !== null));}console.log(isObject(new RegExp('123'))); // trueconsole.log(isObject('123')); // falseconsole.log(isObject(String('123'))); // falseconsole.log(isObject(null)); // false// 判断是否是原始值function isNative (m) { return (m === null || (typeof m !== 'object' && typeof m !== 'function'));}console.log(isNative(new RegExp('123'))); // falseconsole.log(isNative('123')); // trueconsole.log(isNative(String('123'))); // trueconsole.log(isNative(null)); // true
3.检测某个变量是否是函数
当使用闭包时判断是函数后再进行下一步。
function qqq () { let a = 0; let b = function () { a++; console.log(a); }; return b;}let ccc = qqq();console.log(typeof ccc); // functionif (typeof ccc === 'function') { ccc(); // 1 ccc(); // 2 ccc(); // 3 ccc(); // 4}
二. instanceof操作符
通过使用
instanceof
操作符,可以确定一个对象是否是特定构造函数的实例,返回true
或false
。
instanceof
只适用于构造函数创建返回的复杂对象和实例。任何时间判断一个对象(复杂值)是否是
Object
的实例时,它都将返回true
,因为所有对象都继承自Object()
构造函数。
let oFather = function () { this.firstName = 'mazey';};oFather.prototype.lastName = 'qian';// 实例let oSon = new oFather();console.log(oSon instanceof oFather); // true// 继承let nFather = function () {};nFather.prototype = new oFather();nFather.construction = nFather;console.log(nFather.firstName); // undefinedconsole.log(nFather.prototype.lastName); // qianconsole.log(nFather instanceof oFather); // falseconsole.log(new nFather() instanceof nFather); // true// 相对于Object来说console.log('123' instanceof Object); // falseconsole.log(new String('123') instanceof Object); // true 构造出来的实例console.log(null instanceof Object); // false
instanceof使用场景
判断在一个继承关系中实例是否属于它的父类。
// 继承let oFather = function () {};let nFather = function () {};nFather.prototype = new oFather();nFather.construction = nFather;let nSon = new nFather();console.log(nSon instanceof nFather); // trueconsole.log(nSon instanceof oFather); // true
三. in操作符和hasOwnProperty方法
in
操作符可以检查一个对象的属性,包括来自原型链的属性,hasOwnProperty()
方法可以检查来自非原型链属性的对象。
例如现在有一个对象let obj = {name: 'mazey'};
,name
是它自身定义的属性,toString
是它从原型链上继承下来的属性。
let obj = {name: 'mazey'};console.log('name' in obj); // trueconsole.log('toString' in obj); // trueconsole.log('name' in Object); // trueconsole.log(obj.hasOwnProperty('name')); // trueconsole.log(obj.hasOwnProperty('toString')); // falseconsole.log(Object.hasOwnProperty('name')); // true
所以in操作符查找的范围更广一点,可以用hasOwnProperty()
判断是否是对象自身的属性,而不是通过类似obj.prototype.foo = 'foo';
这样定义的。
hasOwnProperty方法使用场景
在实际项目中经常使用for...in...
来遍历对象中可枚举的属性,但是for...in...
常常把原型obj.prototype.xxx
中的属性也列举出来,所以在循环的时候可以加上hasOwnProperty()
方法判断下。
function obj0 () { this.name = 'mazey', this.age = '24'};obj0.prototype.gender = 'male';let obj1 = new obj0();// 打印所有可枚举属性for (let key in obj1) { console.log(key); // name age gender 从原型链上继承下来的属性也会被打印出来}// 过滤掉原型链上的属性for (let key in obj1) { if (obj1.hasOwnProperty(key)) { console.log(key); // name age }}
四. 总结
1.typeof
可以判断使用值的类型,注意null
返回object
。
2.instanceof
验证构造函数构造出来的实例,可以用来判断一个对象是否属于一个父类。
3.hasOwnProperty
方法常常与in
操作符搭配使用,用来遍历一个对象自身的属性。
五. 相关扩展
1.删除对象的属性
若想把一个对象的自身属性完全删除,要使用delete
操作符。
let obj0 = { name: 'mazey', age: 24};// 删除age属性delete obj0.age;console.log(obj0.hasOwnProperty('age')); // falseconsole.log('age' in obj0); // false// 试着删除原型链上的属性 toStringdelete obj0.toStringconsole.log('toString' in obj0); // true
需要注意的是delete
不会删除原型链上的属性。
2.可枚举
每个对象的属性都分为可枚举和不可枚举属性,可以使用propertyIsEnumerable()
方法来检查哪些属性是可枚举的。
每个对象都有一个
propertyIsEnumerable
方法。此方法可以确定对象中指定的属性是否可以被for...in
(for...in语句以任意顺序遍历一个对象的可枚举属性。对于每个不同的属性,语句都会被执行)循环枚举,但是通过原型链继承的属性除外。如果对象没有指定的属性,则此方法返回false
。
有的资料说只要能被for..in
遍历的属性就是可枚举的,实际上要排除从原型链上继承下来的属性,只有自身的属性是可枚举的。
// 第一个构造函数function ConFun0 () { this.firstName = 'mazey';}ConFun0.prototype.firstCom = 'bang';// 第二个构造函数function ConFun1 () { this.secondName = 'qian';}// 继承第一个ConFun1.prototype = new ConFun0();ConFun1.prototype.constructor = ConFun1;// 实例let obj = new ConFun1();obj.girlName = 'cherrie';// 是否可枚举console.log(obj.propertyIsEnumerable('constructor')); // falseconsole.log(obj.propertyIsEnumerable('firstName')); // falseconsole.log(obj.propertyIsEnumerable('firstCom')); // false// 通过原型链继承的属性不是可枚举console.log(obj.propertyIsEnumerable('secondName')); // trueconsole.log(obj.propertyIsEnumerable('girlName')); // truefor (let key in obj) { console.log(key); // secondName girlName (原型链上的属性也会被打印出来->) firstName constructor firstCom}console.log(`---分割线---`);for (let key in obj) { // 过滤掉原型链上的属性 if (obj.hasOwnProperty(key)) { console.log(key); // secondName girlName }}
所以可枚举的属性一定能被for..in
循环遍历出来,但是for...in
循环遍历出来的属性不一定是可枚举的,需排除从原型链上继承下来的属性,这里可以通过hasOwnProperty()
方法过滤掉不可枚举属性。
共同学习,写下你的评论
评论加载中...
作者其他优质文章