对象 (object)
Object 是 JavaScript 的一种 数据类型 。它用于存储各种键值集合和更复杂的实体。Objects 可以通过 Object() 构造函数或者使用 对象字面量 的方式创建
描述
在JavaScript中,几乎所有的对象都是Object类型的实例,它们都会从Object.prototype继承属性和方法,虽然大部分属性都会被覆盖(shadowed)或者说被重写了(overridden)。 除此之外,Object 还可以被故意的创建,但是这个对象并不是一个“真正的对象”(例如:通过 Object.create(null)),或者通过一些手段改变对象,使其不再是一个“真正的对象”(比如说: Object.setPrototypeOf)。
通过原型链,所有的 object 都能观察到 Object 原型对象(Object prototype object)的改变,除非这些受到改变影响的属性和方法沿着原型链被进一步地重写。尽管有潜在的危险,但这为覆盖或扩展对象的行为提供了一个非常强大的机制。
Object 构造函数为给定的参数创建一个包装类对象(object wrapper),具体有以下情况:
- 如果给定值是 null或 undefined,将会创建并返回一个空对象
- 如果传进去的是一个基本类型的值,则会构造其包装类型的对象
- 如果传进去的是引用类型的值,仍然会返回这个值,经他们复制的变量保有和源对象相同的引用地址
当以非构造函数形式被调用时,Object 的行为等同于 new Object()。
构造函数
- Object()
创建一个新的 Object 对象。该对象将会包裹(wrapper)传入的参数
静态方法
- Object.assign()
通过复制一个或多个对象来创建一个新的对象。 - Object.create()
使用指定的原型对象和属性创建一个新对象。 - Object.defineProperty()defineProperty)
给对象添加一个属性并指定该属性的配置。 - Object.defineProperties()defineProperties)
给对象添加多个属性并分别指定它们的配置。 - Object.entries()
返回给定对象自身可枚举属性的 [key, value] 数组。 - Object.freeze()
冻结对象:其他代码不能删除或更改任何属性。 - Object.getOwnPropertyDescriptor()Object/getOwnPropertyDescriptor)
返回对象指定的属性配置。 - Object.getOwnPropertyNames()getOwnPropertyNames)
返回一个数组,它包含了指定对象所有的可枚举或不可枚举的属性名。 - Object.getOwnPropertySymbols()Object/getOwnPropertySymbols)
返回一个数组,它包含了指定对象自身所有的符号属性。 - Object.getPrototypeOf()GetPrototypeOf)
返回指定对象的原型对象。 - Object.is()
比较两个值是否相同。所有 NaN 值都相等(这与==和===不同)。 - Object.isExtensible()isExtensible)
判断对象是否可扩展。 - Object.isFrozen()
判断对象是否已经被冻结。 - Object.isSealed()
判断对象是否已经密封。 - Object.keys()
返回一个包含所有给定对象自身可枚举属性名称的数组。 - Object.preventExtensions()preventExtensions)
防止对象的任何扩展。 - Object.seal()
防止其他代码删除对象的属性。 - Object.setPrototypeOf()setPrototypeOf)
设置对象的原型(即内部 [[Prototype]] 属性)。 - Object.values()
返回给定对象自身可枚举值的数组。
实例属性
- Object.)
一个引用值,指向 Object 构造函数 - Object.)
指向一个对象,当是一个 object 实例化时,使用该对象作为实例化对象的原型
实例方法
- Object.()Object/defineGetter)
将一个属性与一个函数相关联,当该属性被访问时,执行该函数,并且返回该函数的返回值。 - Object.()Object/defineSetter)
将一个属性与一个函数相关联,当该属性被设置时,执行该函数,执行该函数去修改某个属性。 - Object.()Object/lookupGetter)
返回一个函数,该函数通过给定属性的 Object.() 得出。 - Object.()Object/lookupSetter)
返回一个函数,该函数通过给定属性的 Object.() 得出。 - Object.()Object/hasOwnProperty)
返回一个布尔值,用于表示一个对象自身是否包含指定的属性,该方法并不会查找原型链上继承来的属性。 - Object.()Object/isPrototypeOf)
返回一个布尔值,用于表示该方法所调用的对象是否在指定对象的原型链中。 - Object.()Global_Objects/Object/propertyIsEnumerable)
返回个布尔值,用于表示内部属性 [ECMAScript [[Enumerable]] attribute - Object.()Object/toLocaleString)
调用 toString()。 - Object.()toString)
返回一个代表该对象的字符串。 - Object.()valueOf)
返回指定对象的原始值。
示例
给定undefined和null类型使用Object
下面的例子将一个空的 Object 对象存到 o 中:
var o = new Object(); var o = new Object(undefined); var o = new Object(null);
使用Object生成布尔对象object生成布尔对象
下面例子将[Boolean``o 中:
// 等价于 o = new Boolean(true); var o = new Object(true); // 等价于 o = new Boolean(false); var o = new Object(Boolean());
create 创建一个对象
const obj = Object.create({a:1}, {b: {value: 2}}) // 第一个参数为对象,对象为函数调用之后返回新对象的原型对象,第二个参数为对象本身的实例方法(默认不能修改,不能枚举) obj.__ === 1 // true obj.b = 3; con) // 2 //创建一个可写的,可枚举的,可配置的属性p obj2 = Object.create({}, { p: { value: 2, // 属性值 writable: true, // 是否可以重写值 enumerable: true, //是否可枚举 configurable: true //是否可以修改以上几项配置 } }); obj2.p = 3; con) // 3 /* 注意: enumerable 会影响以下 for…in 遍历包括对象原型上属性 */ Object.keys() //只能遍历自身属性 JSON.stringify //只能序列化自身属性
defineProperty
Object.defineProperty(object, prop, descriptor)定义对象属性
// 添加数据属性 var obj = {}; // 1.添加一个数据属性 Object.defineProperty(obj, "newDataProperty", { value: 101, writable: true, enumerable: true, configurable: true }); obj.newDataProperty // 101 // 2.修改数据属性 Object.defineProperty(obj, "newDataProperty", { writable:false }); //添加访问器属性 var obj = {}; Object.defineProperty(obj, "newAccessorProperty", { set: Function (x) { = x; }, get: function () { return ; }, enumerable: true, configurable: true });
注意: 1.第一个参数必须为对象 2.descriptor 不能同时具有 (value 或 writable 特性)(get 或 set 特性)。 3.configurable 为false 时,不能重新修改装饰器
defineProperties
Object.defineProperties(object, {prop1 : descriptor1, prop2 : descriptor2, ...)
var obj = {}; Object.defineProperties(obj, { 'property1': { value: true, writable: true }, 'property2': { value: 'Hello', writable: false } // etc. etc. });
keys
遍历可枚举的属性,只包含对象本身可枚举属性,不包含原型链可枚举属性
let arr = ["a", "b", "c"]; let obj = { foo: "bar", baz: 42 }; let ArrayLike = { 0 : "a", 1 : "b", 2 : "c"}; Object.keys(arr) // ['0', '1', '2'] Object.keys(obj) // ["foo","baz"] Object.keys(ArrayLike) // ['0', '1', '2']
values
遍历可枚举的属性值,只包含对象本身可枚举属性值,不包含原型链可枚举属性值
let arr = ["a", "b", "c"]; let obj = { foo: "bar", baz: 42 }; let ArrayLike = { 0 : "a", 1 : "b", 2 : "c"}; Object.values(arr) // ["a", "b", "c"] Object.values(obj) // ["bar",42] Object.values(ArrayLike) // ["a", "b", "c"]
assign
Object.assign( target, source, source1 ) 方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false)
const target = { a: 1, b: 1 }; const source1 = { b: 2, c: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3} // 特殊情况: let obj = {a: 1}; Object.assign(obj, undefined) === obj // true Object.assign(obj, null) === obj // true Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3] Object.assign //方法实行的是浅拷贝,而不是深拷贝。 const obj1 = {a: {b: 1}}; const obj2 = Object.assign({}, obj1); obj1.a.b = 2; con) //2 obj2.a.b = 3 con) //3
getPrototypeOf
获取指定对象的原型(内部[[Prototype]]属性的值)
const prototype1 = {}; const object1 = Object.create(prototype1); con(object1) === prototype1); // true // 注意:Object.getPrototypeOf(Object) 不是 Object.prototype Object.getPrototypeOf( Object ) === Func; // true
setPrototypeOf
设置一个指定的对象的原型
const obj = {a: 1}, proto = {b:2} Object.setPrototypeOf(obj, proto) obj.__proto__ === proto //true
getOwnPropertyNames
与keys相似,但包含遍历包含不可枚举属性
var my_obj = Object.create({}, { getFoo: { value: function() { return ; }, enumerable: false } }); my_obj.foo = 1; Object.getOwnPropertyNames(my_obj).sort() // ["foo", "getFoo"]
getOwnPropertyDescriptor
获取该属性的描述对象
let obj = { foo: 123 }; Object.getOwnPropertyDescriptor(obj, 'foo') // { value: 123, writable: true, enumerable: true, configurable: true }
getOwnPropertyDescriptors
返回指定对象所有自身属性(非继承属性)的描述对象
// Object.getOwnPropertyDescriptors 方法,返回指定对象所有自身属性(非继承属性)的描述对象。 const obj = { foo: 123, get bar() { return 'abc' } }; con(obj)) // { foo:{ value: 123, // writable: true, // enumerable: true, // configurable: true }, // bar:{ get: [Function: bar], // set: undefined, // enumerable: true, // configurable: true } // }
使用场景: Object.assign() 方法只能拷贝源对象的可枚举的自身属性,同时拷贝时无法拷贝属性的特性,而且访问器属性会被转换成数据属性,也无法拷贝源对象的原型
Object.create() 方法可以实现上面说的这些,配合getPrototypeOf,以及getOwnPropertyDescriptors实现全面浅拷贝
Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj) );
entries
分割对象
const obj = { foo: 'bar', baz: 42 }; con(obj)); // [ ['foo', 'bar'], ['baz', 42] ] // array like object const obj = { 0: 'a', 1: 'b', 2: 'c' }; con(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ] // string Object.entries('abc') // [['0', 'a'], ['1', 'b'], ['2', 'c']] Object.entries(100) // []
is
它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致
Object.is('foo', 'foo') // true Object.is({}, {}) // false // 不同于 === 之处 +0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
preventExtensions
让一个对象变的不可扩展,也就是永远不能再添加新的属性&isExtensible 判断一个对象是否可扩展
let empty = {} Object.isExtensible(empty) //true em = 1 //添加成功 //将对象变为不可拓展 Object.preventExtensions(empty) Object.isExtensible(empty) //false em = 2 //静默失败,不抛出错误 em = 5 //修改a属性值为5 修改成功
总结: 1.preventExtensions 可以让这个对象变的不可扩展,也就是不能再有新的属性。 2.需要注意的是不可扩展的对象的属性通常仍然可以被删除。 3.尝试给一个不可扩展对象添加新属性的操作将会失败,不过可能是静默失败,也可能会抛出 TypeError 异常(严格模式)。 4.Object.preventExtensions 只能阻止一个对象不能再添加新的自身属性,仍然可以为该对象的原型添加属性。
seal
将一个对象密封 isSealed 判断一个对象是否为密封的
密封对象是指那些不能添加新的属性,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性,但可能可以修改已有属性的值的对象。
- 先讲seal 方法:
var o2 = {b: 1} o2.d = 2 //添加成功 var obj2 = Object.seal(o2); obj2 === o2 //true 方法返回原对象,栈指针指向同一块内存 Object.isSealed(o2) // true o2.b = 111 //修改b属性值成功 o2.f = 222 //静默失败,属性f没有成功添加 delete o2.b //静默失败,属性b没有成功删除
- 讲isSealed 方法:
let o = {}; Object.isSealed(o) //false // 之后通过Object.preventExtensions方法将空对象设置为不可扩展。 Object.preventExtensions(o); Object.isSealed(o) // true //但是如果为非空对象呢? let o2 = {a: 1} Object.preventExtensions(o2); Object.isSealed(o2) // false //因为属性 a 是可配置的(configurable为true),所以不是密封的对象,修改方法如下: let o2 = {a: 1} Object.preventExtensions(o2); Object.defineProperty(o2, "a", { configurable: false }); Object.isSealed(o2) //true
总结: 1.密封一个对象会让这个对象变的不能添加新属性,且所有已有属性会变的不可配置。 2.属性不可配置的效果就是属性变的不可删除,以及一个数据属性不能被重新定义成为访问器属性,或者反之。 3.但属性的值仍然可以修改。 4.尝试删除一个密封对象的属性或者将某个密封对象的属性从数据属性转换成访问器属性,结果会静默失败或抛出TypeError 异常(严格模式)。
freeze
冻结一个对象&isFrozen 判断一个对象是否已经被冻结
冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性的对象。也就是说,这个对象永远是不可变的。
1.先讲freeze 方法:
let o3 = {a: 1} o3.b = 2 //添加属性b成功 Object.freeze(o3) Object.isFrozen(o3) //true 对象已被冻结 o3.a = 2 //修改属性a值失败 o3.c = 5 //添加属性c失败 delete o3.b //删除属性b失败
2.再讲isfrozen 方法:
let o4 = {a: 1} o4.b = 2 // 添加属性b成功 Object.priventExtensions(o4) Object.defineProperties(o4, { a: {configurable: false, writable: false}, b: {configurable: false, writable: false} }) Object.isFrozen(o4) //true o4 已经被冻结
hasOwnProperty
方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性 let o = {a: 1 } o.hasOwnProperty('a') //true o.hasOwnProperty('b') //false 对象自身没有属性b o.hasOwnProperty('toString'); //false 不能检测对象原型链上的属性 如何遍历一个对象的所有自身属性,例子: var buz = { fog: 'stack' }; for (var name in buz) { if (name)) { con("this is fog (" + name + ") for sure. Value: " + buz[name]); } else { con(name); // toString or something else } }
isPrototypeOf
// isPrototypeOf方法用于测试一个对象是否存在于另一个对象的原型链上 function Foo() {} function Bar() {} function Baz() {} Bar.prototype = Object.create); Baz.prototype = Object.create); var baz = new Baz(); con(Baz.(baz)); // true con(Bar.(baz)); // true con(Foo.(baz)); // true con(Object.(baz)); // true
propertyIsEnumerable
指定的属性是否可枚举
obj.propertyIsEnumerable(prop) prop为被测试的属性名 // 1. 一般情况下 var o = {}; var a = []; o.prop = 'is enumerable'; a[0] = 'is enumerable'; o.propertyIsEnumerable('prop'); // 返回 true a.propertyIsEnumerable(0); // 返回 true // 2. 浏览器内置对象 var a = ['is enumerable']; a.propertyIsEnumerable(0); // 返回 true a.propertyIsEnumerable('length'); // 返回 false Ma('random'); // 返回 false ('Math'); // 返回 false //3. 自身属性和继承属性(原型链上propertyIsEnumerable不被考虑) var fn = function(){ = '123'; } = { prototypeProp: true} var o = new fn() o.propertyIsEnumerable('prop') // true o.propertyIsEnumerable('prototypeProp') // false
caller
返回当前函数的调用者
function test(){ i == null){ alert("JavaScript顶层作用域调用了test()函数"); }else{ alert( + "函数调用了test()函数"); } }; test(); // JavaScript顶层作用域调用了test()函数 function callTest(){ test(); } callTest(); // function callTest(){ test(); }函数调用了test()函数 function callTest2(){ // setTimeout()或setInterval()中定时执行的函数也属于顶层作用域调用 setTimeout(test, 5000); // JavaScript顶层作用域调用了test()函数 } callTest2();
valueOf
需要返回对象的原始值
备注:js对象中的valueOf()方法和toString()方法非常类似,但是,当需要返回对象的原始值而非字符串的时候才调用它,尤其是转换为数字的时候。如果在需要使用原始值的上下文中使用了对象,JavaScript就会自动调用valueOf()方法。
const o = {a: 1, valueOf: function(){ return 123123 } } Number(o) //123123 // 给大家出一个题 const o2 = { x: 1, valueOf: function(){ return } } if(o2 == 1 && o2 == 2 && o2 == 3){ con('down') con) }else{ con('faild') } // Array:返回数组对象本身 var array = ["CodePlayer", true, 12, -5]; array.valueOf() === array; // true // Date:当前时间距1970年1月1日午夜的毫秒数 var date = new Date(2013, 7, 18, 23, 11, 59, 230); da() // 30 // Number:返回数字值 var num = 15.26540; num.valueOf() // 15.2654 // 布尔:返回布尔值true或false var bool = true; bool.valueOf() === bool // true // new一个Boolean对象 var newBool = new Boolean(true); // valueOf()返回的是true,两者的值相等 newBool.valueOf() == newBool // true // 但是不全等,两者类型不相等,前者是boolean类型,后者是object类型 newBool.valueOf() === newBool // false // Function:返回函数本身 function foo(){ } () === foo // true var foo2 = new Function("x", "y", "return x + y;"); () === foo2 // true // Object:返回对象本身 var obj = {name: "张三", age: 18}; obj.valueOf() === obj // true // String:返回字符串值 var str = ";; () === str // true // new一个字符串对象 var str2 = new String(";); // 两者的值相等,但不全等,因为类型不同,前者为string类型,后者为object类型 () === str2 // false
getOwnPropertySymbols
在给定对象自身上找到的所有 Symbol 属性的数组。
var obj = {}; var a = Symbol("a"); var b = Symbol.for("b"); obj[a] = "localSymbol"; obj[b] = "globalSymbol"; var objectSymbols = Object.getOwnPropertySymbols(obj); con); // 2 con(objectSymbols) // [Symbol(a), Symbol(b)] con(objectSymbols[0]) // Symbol(a)
toString toLocalString
toString 方法不做过多介绍
区别:
当被转化的值是个时间对象时,toLocaleString会将转化的结果以本地表示。
(new Date).toString(); //"Mon Nov 06 2017 13:02:46 GMT+0800 (China Standard Time)" (new Date).toLocaleString(); //"2017/11/6 下午1:03:12"
另外当被转化的值是个时间戳时,toLocaleString会把时间戳每三位添加一个逗号,代码如下。
(new Date())).toLocaleString() //"1,509,944,637,000" (new Date())).toString() //"00" call apply bind 大家自己回去研究
length
Object.length //1
name
Object.name //"Object"