摘要:需要链接标准参考教程对象阮一峰标准构造器函数可能是最重要的对象之一,尽管我们从来不会直接调用它。该方法返回被冻结的对象。
Object 需要链接: MDN —— Object JavaScript标准参考教程(Object对象)——阮一峰
标准构造器函数Object可能是JavaScript最重要的对象之一,尽管我们从来不会直接调用它。每当使用一个对象直接量时,都会隐式调用它:
var a = {}; // 等同于var a = new Object()
var b = {x:1,y:2}; // 等同于var b = new Object({x:1,y:2});
构造函数定义了数据类型,所以表达式var a = new Object()表明两件事情:a是Object的一个实例,而a的原型是Object.prototype。我们用对象字面量创建的每个对象都会获得由Object.prototype定义的行为
以下将讨论几个常用的主要的属性方法 1. Object() // 首先,将Object作为构造函数调用和对象字面量直接定义是等价的
var o = {};
var o2 = new Object();
// 注意这里所说的等价不是指相等,是指其本身和原型继承相同
// 当然也可以
var a = {};
var a2 = new Object(a);
console.log(a===a2); // true
Object本身作为工具方法
// 返回一个Object构造器实例
var obj = Object();
console.log(obj instanceof Object); // true
// 返回一个字符串构造器实例
var str = Object("string");
console.log(str instanceof Object); // true 等价 new String("string")
// 返回一个数字构造器实例
var num = Object(123);
console.log(num instanceof Object); // true 等价 new Number(123)
// 返回一个布尔构造器实例
var boo = Object(true); // 等价 new Boolean(true)
var boo2 = Object(false);
console.log(boo instanceof Object && boo2 instanceof Object); // true
// null存在的意义在于对象引用之中,null值最初含义为:没有引用任何对象
// null型只能取null一个值,null值是一个字面量,但是对null进行typeof结果为对象
console.log(typeof null); // object
console.log(Object(null) instanceof Object); // true
// 对null调用Object方法,返回一个空对象
// undefined型也只能取undefined一个值,对undefined进行typeof ,值为undefined
console.log(typeof undefined); // undefined
console.log(Object(undefined) instanceof Object); // true
// 也是返回一个空对象
Object本身当作工具方法使用时,可以将任意值转为对象。这个方法常用于保证某个值一定是对象。如果参数是原始类型的值,Object方法返回对应的包装对象的实例
Object()传入参数为基本类型值,则返回值为其类型的构造函数的实例。
上面探讨的是基础类型值,那如果是引用类型值呢?
var arr = [1,2,3];
console.log(Object(arr)); // 把原对象返回了
console.log(Object(arr)===arr); // true
var fn = function () {}; // 把原函数返回了
console.log(Object(fn)); // function () {}
console.log(Object(fn)===fn); // true
var obj = {x:"obj.x"};
console.log(Object(obj)); // [object Object]
console.log(Object(obj)===obj); // true
// 一个判断是否是对象的函数
function judgeObj(obj) {
return Object(obj)===obj? true : false;
}
console.log(judgeObj([])); // true
console.log(judgeObj(true)); // false
console.log(judgeObj({})); // true
console.log(judgeObj(123)); // false
当Object()传入的参数是引用类型值,则会返回原对象;
2. Object.keys(obj)
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 (两者的主要区别是 一个 for-in 循环还会枚举其原型链上的属性)。
受Enumerable条件限制,且不可枚举原型链中的属性
// 无法枚举到原型链中的属性
var obj = Object.create({y:20});
obj.x = 10;
console.log(Object.keys(obj)); // "x"
// 无法枚举Enumerable为false属性
Object.defineProperty(obj,"z",{
value:"z",
enumerable:false
})
console.log(Object.keys(obj)); // "x"
// 对于数组对象
var arr = ["a","b","c"];
console.log(Object.keys(arr)); // "0,1,2"
// 对于随机排列的数组对象
var obj_ramdom = {100:"a",2:"b",50:"c"};
console.log(Object.keys(obj_ramdom)); // "2,50,100"
详细说明:MDN —— Object.keys()
3. Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames 返回一个数组,该数组对元素是 obj 自身拥有的枚举或不可枚举属性名称字符串。 数组中枚举属性的顺序与通过 for...in 循环(或 Object.keys)迭代该对象属性时一致。 数组中不可枚举属性的顺序未定义。
不受Enumerable条件限制,但不可枚举原型链中属性
如果你只要获取到可枚举属性,查看 Object.keys 或用 for...in循环(还会获取到原型链上的可枚举属性,不过可以使用hasOwnProperty()方法过滤掉)。
// 无法枚举到原型链中的属性
var obj = Object.create({y:20});
obj.x = 10;
console.log(
Object.getOwnPropertyNames(obj)
); // "x"
// 可以枚举Enumerable为false的属性
Object.defineProperty(obj,"z",{
value:"z",
enumerable:false
})
console.log(
Object.getOwnPropertyNames(obj)
); // "x,z"
// 对于数组对象(length属性为不可枚举)
var arr = ["a","b","c"];
console.log(
Object.getOwnPropertyNames(arr)
); // "0,1,2,length"
// 对于随机排列的数组对象
var obj_ramdom = {100:"a",2:"b",50:"c"};
console.log(
Object.getOwnPropertyNames(obj_ramdom)
); // "2,50,100"
详细:MDN —— Object.getOwnPropertyNames()
for-in、Object.keys、Object.getOwnPropertyNames特点区分
三者关于是否受Enumerable的限制测试
var obj = {x:10,y:20};
Object.defineProperty(obj,"z",{
value:30,
enumerable:false,
});
// for-in
for (var a in obj) {
console.log(a); // "x,y"
}
// Object.keys
console.log(
Object.keys(obj) // "x,y"
);
// Object.getOwnPropertyNames()
console.log(
Object.getOwnPropertyNames(obj) // "x,y,z"
);
三者关于是否可以枚举原型链的测试
function Test() {
this.x = 10;
this.y = 20;
}
Test.prototype.z = 30; // z为原型链属性
var obj = new Test();
// for-in
for (var a in obj) {
console.log(a) // "x,y,z"
}
// Object-keys
console.log(
Object.keys(obj) // "x,y"
)
// Object.getOwnPropertyNames()
console.log(
Object.getOwnPropertyNames(obj) // "x,y"
)
我们如何记忆呢?就记最特殊的!
for-in:只有它可以枚举原型链里的属性,并且它也不是Object对象的方法 Object.getOwnPropertyNames():只有它可以享有Enumerable的"豁免权",不管如何设置只要是这个对象上的自有属性都可以枚举到! 对象属性控制相关方法 四个相关的方法在这里先列出,这里要要提到数据属性和访问器属性《JS高程》—— 数据属性与访问器属性
强荐:阮一峰 —— 属性描述对象
4. Object.defineProperty()Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
5. Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptor() 返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
// 采用Object.defineProperty定义的属性,如果不显示定义
// enumerable,configurable,writable值默认为false(与对象字面量相反)
var obj = {};
Object.defineProperty(obj,"x",{
value:"obj.x"
});
// 使用Object.getOwnPropertyDescriptor()获取属性对象
var obj_attr = Object.getOwnPropertyDescriptor(obj,"x");
for (var i in obj_attr) {
document.write(i+" : "+obj_attr[i]+"
")
}
// 默认下数据属性都是false
6. Object.defineProperties()
Object.defineProperties() 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
var obj = {};
Object.defineProperties(obj,{
x:{
value:"obj.x",
writable:true,
enumerable:true,
configurable:true
},
y:{
value:"obj.y",
writable:true,
enumerable:true,
configurable:true
},
z:{
value:"obj.z"
}
})
console.log(Object.keys(obj)); // "x,y" z属性enumerable默认为false
// 当然,z属性的数据属性都是false
冲突:
《JavaScript编程全解》:只要将get属性与set属性指定为相应的函数,就能够定义一个只能够通过访问器getter和setter来访问值的属性。访问器与value属性是互相排斥的,也就是说,如果指定了value属性的值,访问器(包括get和set)就会失效;反之,如果指定了访问器(get或set中的某一个亦或是都存在),value属性就会失效。
《JS高程3》:不一定非要同时指定getter和setter。只指定getter意味着属性是不能写,尝试写入属性会被忽略。在严格模式下,尝试写入只指定了getter函数的的属性会抛出错误。类似地,没有指定setter函数的属性也不能读,否则在非严格模式下会返回undefined,在严格模式下会抛出错误。
var obj = {_x:10};
// 定义一个访问器属性
Object.defineProperty(obj,"x",{
get:function () {
return this._x
}
})
// 读取obj.x会隐式调用访问器属性,返回obj._x的值(下划线代表此属性只能通过访问器读写)
console.log(obj.x); // 10
// 尝试为访问器属性赋值
// 直接赋值
obj.x = "aaa";
console.log(obj.x); // 10 赋值失败
// 获取obj.x的attributes
var objxAttr = Object.getOwnPropertyDescriptor(obj,"x");
for (var i in objxAttr) {
document.write(
i+" | "+objxAttr[i]+"
"
)
}
// get | function () { return this._x }
// set | undefined
// enumerable | false
// configurable | false
// 不可写的原因是value属性与访问器属性冲突,即(get、set)与value属性冲突
// 可以通过查看attributes属性,判断属性是否是访问器属性还是数据属性,存在set或者get的是访问器属性
具体内容请移步至相关知识点进行更深入学习,这里只介绍方法基础用法
对象状态相关方法 Object.preventExtensions()如果一个对象可以添加新的属性,则这个对象是可扩展的。preventExtensions 可以让这个对象变的不可扩展,也就是不能再有新的属性。需要注意的是不可扩展的对象的属性通常仍然可以被删除。尝试给一个不可扩展对象添加新属性的操作将会失败,不过可能是静默失败,也可能会抛出 TypeError 异常(严格模式)。
Object.preventExtensions 只能阻止一个对象不能再添加新的自身属性,仍然可以为该对象的原型添加属性。然而Object.preventExtensions会阻止一个对象将__proto__属性重新指向另一个对象。
// Object.preventExtensions将原对象变的不可扩展,并且返回原对象
var obj = {};
var obj2 = Object.preventExtensions(obj);
alert(obj===obj2); // true
obj.x = "obj.x";
alert(obj.x); // undefined
// 采用对象字面量定义的对象默认可扩展
var o = {};
alert(Object.isExtensible(o)); // true
// 当然,通过调用方法可以阻止
Object.preventExtensions(o);
alert(Object.isExtensible(o)); // false
// 使用Object.defineProperty方法为一个不可扩展的对象添加新属性会抛出异常.
var o2 = {a:"a"};
Object.preventExtensions(o2);
Object.defineProperty(o2,"b",{
value:"test"
})
// "Uncaught TypeError: Cannot define property:b, object is not extensible."
// 一个不可扩展对象的原型是不可更改的,__proto__是个非标准魔法属性,可以更改一个对象的原型.
var b = Object.preventExtensions({x:1,y:2});
b.__proto__ = {a:10,b:20}; // "Uncaught TypeError: #