本文深入解析JavaScript中对象属性的核心操作。详细讲解delete运算符删除自有属性与继承属性的区别,以及不可配置属性的限制。介绍使用in运算符、hasOwnProperty和propertyIsEnumerable检测属性的方法,并探讨isPrototypeOf、instanceof及类属性的获取技巧,帮助开发者精准控制对象状态。
JavaScript对象属性操作详解:删除、检测与枚举
1.移除属性
delete关键字可用于移除对象属性
示例代码:
delete person.age //此时person对象不再拥有age属性
delete person['age'] //亦可采用此方式
delete仅切断属性与宿主对象的关联,不操作属性内的子属性。执行delete a.p后,b.x仍为1
var a = {p:{x:1}};
var b = a.p;
console.log(a.p.x); //1
delete a.p;
console.log(a.p.x); //TypeError a.p is undefined
console.log(a.p); //undefined
console.log(b.x); //1
delete仅能移除自有属性,无法直接移除继承属性(需从定义该属性的原型对象上删除,这将影响所有继承自该原型的对象)
function inherit(p){
if(p == null){ // 不能从null中继承
throw TypeError();
}
if(Object.create){ //如果有这个方法就直接使用
return Object.create(p);
}
var t = typeof p;
if(t !== "object" || t !== "function"){ //要继承的对象 类型要符合
throw TypeError();
}
function f(){ }; //定义一个空的构造函数
f.prototype = p; //原型指向要继承的对象p
return new f(); //创建f对象,此对象继承自p
}
var obj = {x:1};
var obj1 = inherit(obj);
obj1.y = 2;
console.log("x = "+obj1.x+" y = "+obj1.y); //x = 1 y = 2
delete obj1.x;
delete obj1.y;
console.log("x = "+obj1.x+" y = "+obj1.y); //x = 1 y = undefined
仅可配置的属性支持使用delete 例如
delete Object.prototype; // 不能删除 不可配置
var x = 1;
delete this.x; //不能删除
this.y = 1;
delete y; //这样可以删除
function f(){ }
delete this.f; //不能删除
检测对象属性的方法
2.检测属性
使用“in”运算符
in运算符要求左操作数为字符串或可转换为字符串,右操作数为对象
var data = [5,6,7];
console.log("0" in data); //有下标0
console.log(1 in data); //1可以转换成"1"
console.log("4" in data); //下标只有 1 2 3
var obj = {x:1};
console.log("x" in obj); //true
console.log("y" in obj); //false
console.log("toString" in obj); //true 因为obj继承了这个方法
使用hasOwnProperty()或propertyIsEnumerable() ——后者为前者的增强版 顾名思义
var obj = {x:1};
console.log(obj.hasOwnProperty("x")); //true
console.log(obj.hasOwnProperty("y")); //false
console.log(obj.hasOwnProperty("toString")); //false 因为obj继承了这个方法,但不是它自己的
仅当属性为自有属性且可枚举时,后者返回true
var obj = {x:1};
console.log(obj.propertyIsEnumerable("x")); //true
console.log(obj.propertyIsEnumerable("y")); //false
console.log(obj.propertyIsEnumerable("toString")); //false 因为obj继承了这个方法,但不是它自己的
console.log(Object.prototype.propertyIsEnumerable("toString")); //false 因为最原始的的 toString就是不可枚举的
亦可直接使用“!==”运算符进行判断
var obj = {x:1};
console.log(obj.x !== undefined);//true
console.log(obj.y !== undefined);//false
console.log(obj.toString !== undefined); //true
3.枚举属性
var obj = {x:1,y:2};
for(p in obj){
console.log(p);//x y
console.log(obj.p);// undefined undefined
console.log(obj[p]);//1 2
}
原型链与对象类型检测
扩展1:
每个对象均关联有原型(prototype)、类(class)、可扩展性(extensible) 检测对象是否为另一对象的原型(或处于原型链中),可使用isPrototypeOf()方法
var p = {x:1}; //p原型对象继承自Object.prototype
var o = Object.create(p); //o对象继承自p
console.log(p.isPrototypeOf(o));//true
console.log(Object.prototype.isPrototypeOf(o));//true
console.log(Object.prototype.isPrototypeOf(p));//true
isPrototypeOf()方法与instanceof运算符功能相似 instanceof运算符要求左操作数为对象,右操作数标识对象的类。若左侧对象是右侧类的实例,表达式返回true,否则返回false
var p = {x:1};
console.log(p instanceof Object);//true
var d = new Date();
console.log(d instanceof Date);//true
console.log(d instanceof Object);//true
console.log(d instanceof Number);//false
扩展2:
对象的类属性为字符串,用于表示对象的类型信息
通常调用toString()方法后返回形如[object class]的字符串
例如
示例代码:
var obj = {x:1,y:2};
console.log(obj.toString());//[object Object]
因此,可通过从返回字符串中提取“class”字段来获取对象的类,使用slice(8,-1) 例如
function classOf(obj){ // 找出类名
if(obj === null){
return "Null";
}
if(obj === undefined){
return "Undefined";
}
return Object.prototype.toString.call(obj).slice(8,-1);
}
console.log(classOf(1)); //Number
//注意,实际上是这些类型的变量调用toString()方法,而不是通过他们自身直接调用
//console.log(1.toString()); //会报错
var a = 1;
console.log(Number(1).toString()); //1
console.log(a.toString()); //1
console.log({x:1}.toString()); //[object Object]
console.log(classOf(1)); //Number
console.log(classOf("")); //String
console.log(classOf("str")); //String
console.log(classOf(null)); //Null
console.log(classOf(false)); //Boolean
console.log(classOf({})); //Object
console.log(classOf([])); //Array
console.log(classOf(new Date())); //Date
function f(){}
console.log(classOf(new f())); //Object