一. typeof操作符
typeof
操作符用于返回正在使用值的類型。
// 使用原始值
let mNull = null;
let mUndefined = undefined;
let mString = 'mazey';
let mNumber = 123;
let mBoolean = true;
let mFunction = function () {
return true;
};
// 用構(gòu)造函數(shù)的方式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); // object
console.log(typeof mUndefined); // undefined
console.log(typeof mString); // string
console.log(typeof mNumber); // number
console.log(typeof mBoolean); // boolean
console.log(typeof mFunction); // function
console.log(typeof oString); // object
console.log(typeof oRegExp); // object
console.log(typeof oFunction); // function
console.log(typeof oObj); // object
console.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]+$/); // false
console.log(RegExp('^[0-9]+$') === /^[0-9]+$/); // false
綜上可以看出現(xiàn)版本RegExp
和String Number
一樣屬于JavaScript的原始值读跷。
Math
作為JavaScript中的靜態(tài)對象回返回什么呢?
console.log(typeof Math); // object
console.log(typeof Math.PI); // number
console.log(typeof Math.ceil); // function
所以Math
的__proto__
還是Object
禾唁,typeof
還能返回對象的屬性和方法的類型效览。
typeof使用場景
- 判斷某個變量是否已定義
console.log(typeof aaa); // 'undefined'
// 判斷
if (typeof bbb === 'undefined') {
console.log('變量未定義');
}
- 區(qū)分原始值和復(fù)雜值(對象值)
因為復(fù)雜值往往返回object
,當(dāng)然有個例外就是原始值里面的null
也返回object
荡短,然后function
作為Object
的實例也是復(fù)雜值丐枉。
// 判斷是否時復(fù)雜值(對象值)
function isObject (m) {
return (typeof m === 'function' || (typeof m === 'object' && m !== null));
}
console.log(isObject(new RegExp('123'))); // true
console.log(isObject('123')); // false
console.log(isObject(String('123'))); // false
console.log(isObject(null)); // false
// 判斷是否是原始值
function isNative (m) {
return (m === null || (typeof m !== 'object' && typeof m !== 'function'));
}
console.log(isNative(new RegExp('123'))); // false
console.log(isNative('123')); // true
console.log(isNative(String('123'))); // true
console.log(isNative(null)); // true
- 檢測某個變量是否是函數(shù)
當(dāng)使用閉包時判斷是函數(shù)后再進(jìn)行下一步。
function qqq () {
let a = 0;
let b = function () {
a++;
console.log(a);
};
return b;
}
let ccc = qqq();
console.log(typeof ccc); // function
if (typeof ccc === 'function') {
ccc(); // 1
ccc(); // 2
ccc(); // 3
ccc(); // 4
}
二. instanceof操作符
通過使用
instanceof
操作符掘托,可以確定一個對象是否是特定構(gòu)造函數(shù)的實例瘦锹,返回true
或false
。
instanceof
只適用于構(gòu)造函數(shù)創(chuàng)建返回的復(fù)雜對象和實例。
任何時間判斷一個對象(復(fù)雜值)是否是
Object
的實例時弯院,它都將返回true
辱士,因為所有對象都繼承自Object()
構(gòu)造函數(shù)。
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); // undefined
console.log(nFather.prototype.lastName); // qian
console.log(nFather instanceof oFather); // false
console.log(new nFather() instanceof nFather); // true
// 相對于Object來說
console.log('123' instanceof Object); // false
console.log(new String('123') instanceof Object); // true 構(gòu)造出來的實例
console.log(null instanceof Object); // false
instanceof使用場景
判斷在一個繼承關(guān)系中實例是否屬于它的父類听绳。
// 繼承
let oFather = function () {};
let nFather = function () {};
nFather.prototype = new oFather();
nFather.construction = nFather;
let nSon = new nFather();
console.log(nSon instanceof nFather); // true
console.log(nSon instanceof oFather); // true
三. in操作符和hasOwnProperty方法
in
操作符可以檢查一個對象的屬性颂碘,包括來自原型鏈的屬性,hasOwnProperty()
方法可以檢查來自非原型鏈屬性的對象辫红。
例如現(xiàn)在有一個對象let obj = {name: 'mazey'};
凭涂,name
是它自身定義的屬性,toString
是它從原型鏈上繼承下來的屬性贴妻。
let obj = {name: 'mazey'};
console.log('name' in obj); // true
console.log('toString' in obj); // true
console.log('name' in Object); // true
console.log(obj.hasOwnProperty('name')); // true
console.log(obj.hasOwnProperty('toString')); // false
console.log(Object.hasOwnProperty('name')); // true
所以in操作符查找的范圍更廣一點切油,可以用hasOwnProperty()
判斷是否是對象自身的屬性,而不是通過類似obj.prototype.foo = 'foo';
這樣定義的名惩。
hasOwnProperty方法使用場景
在實際項目中經(jīng)常使用for...in...
來遍歷對象中可枚舉的屬性澎胡,但是for...in...
常常把原型obj.prototype.xxx
中的屬性也列舉出來,所以在循環(huán)的時候可以加上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
}
}
四. 總結(jié)
-
typeof
可以判斷使用值的類型攻谁,注意null
返回object
。 -
instanceof
驗證構(gòu)造函數(shù)構(gòu)造出來的實例弯予,可以用來判斷一個對象是否屬于一個父類戚宦。 -
hasOwnProperty
方法常常與in
操作符搭配使用,用來遍歷一個對象自身的屬性锈嫩。
五. 相關(guān)擴(kuò)展
1. 刪除對象的屬性
若想把一個對象的自身屬性完全刪除受楼,要使用delete
操作符。
let obj0 = {
name: 'mazey',
age: 24
};
// 刪除age屬性
delete obj0.age;
console.log(obj0.hasOwnProperty('age')); // false
console.log('age' in obj0); // false
// 試著刪除原型鏈上的屬性 toString
delete obj0.toString
console.log('toString' in obj0); // true
需要注意的是delete
不會刪除原型鏈上的屬性呼寸。
2. 可枚舉
每個對象的屬性都分為可枚舉和不可枚舉屬性艳汽,可以使用propertyIsEnumerable()
方法來檢查哪些屬性是可枚舉的。
每個對象都有一個
propertyIsEnumerable
方法对雪。此方法可以確定對象中指定的屬性是否可以被for...in
(for...in語句以任意順序遍歷一個對象的可枚舉屬性河狐。對于每個不同的屬性,語句都會被執(zhí)行)循環(huán)枚舉瑟捣,但是通過原型鏈繼承的屬性除外馋艺。如果對象沒有指定的屬性,則此方法返回false
迈套。
有的資料說只要能被for..in
遍歷的屬性就是可枚舉的丈钙,實際上要排除從原型鏈上繼承下來的屬性,只有自身的屬性是可枚舉的交汤。
// 第一個構(gòu)造函數(shù)
function ConFun0 () {
this.firstName = 'mazey';
}
ConFun0.prototype.firstCom = 'bang';
// 第二個構(gòu)造函數(shù)
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')); // false
console.log(obj.propertyIsEnumerable('firstName')); // false
console.log(obj.propertyIsEnumerable('firstCom')); // false
// 通過原型鏈繼承的屬性不是可枚舉
console.log(obj.propertyIsEnumerable('secondName')); // true
console.log(obj.propertyIsEnumerable('girlName')); // true
for (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
循環(huán)遍歷出來,但是for...in
循環(huán)遍歷出來的屬性不一定是可枚舉的,需排除從原型鏈上繼承下來的屬性芙扎,這里可以通過hasOwnProperty()
方法過濾掉不可枚舉屬性星岗。