此文章用于归纳Object的所有方法
在JavaScript中,
object
是所有对象的基础(原型链的顶端),所以,他具有的这些方法、属性,也是所有对象都具有的方法、属性,可能具体到方法会有所不同(因为原型覆盖,重写),但是属性名都相同,内容也有相似的地方。
object
的每个实例都具有下列属性和方法(Object .prototype
里的方法):
-
constructor
:构造函数,保存着用于创建当前对象的函数。例子如下:
var obj = new Object();
console.log(obj.constructor);//function Object() { [native code] }
[native code]
是什么呢?我大概的把它理解为由JS引擎自己内部实现的代码,而非JS代码。
-
hasOwnProperty('propertyName')
:该方法接受一个参数(传入的参数必须是以字符串的形式),用于检查传入的属性名对应的属性是否是当前对象自己拥有的(而非通过原型链继承过来的)。如果是,返回true
,不是,返回false
。例子如下:
var obj = new Object();
console.log(obj.hasOwnProperty('toString'));//false
obj.toString = function(){return 123};
console.log(obj.hasOwnProperty('toString'));//true
-
isPrototypeOf(obj)
:该方法接受一个参数,用于检查传入的对象的原型链是否包含当前对象。例子如下:
function Foo() {}
function Bar() {}
function Baz() {}
Bar.prototype = Object.create(Foo.prototype);
Baz.prototype = Object.create(Bar.prototype);
var baz = new Baz();
console.log(Baz.prototype.isPrototypeOf(baz)); // true
console.log(Bar.prototype.isPrototypeOf(baz)); // true
console.log(Foo.prototype.isPrototypeOf(baz)); // true
console.log(Object.prototype.isPrototypeOf(baz)); // true
特别注意,不要和instanceof
弄混淆了。
A.isPrototypeOf(B) //判断的是A对象是否存在于B对象的原型链之中
A instanceof B //判断的是B.prototype是否存在与A的原型链之中
-
propertyIsEnumerable('propertyName')
:接受一个参数,与hasOwnProperty('propertyName')
类似,只能传入字符串参数,其作用是用来检查传入参数对应的属性是否是可枚举的,如果可枚举返回true
,就可以用for in
循环,反之不行,返回false
。其代码是:
var obj = {};
Object.defineProperty(obj, 'prop1', {
enumerable: false,
});
Object.defineProperty(obj, 'prop2', {
enumerable: true,
});
console.log(obj.propertyIsEnumerable('prop1'));//false
console.log(obj.propertyIsEnumerable('prop2'));//true
-
toLocaleString()
:返回对象的字符串表示,该字符串与区域设置有关。其返回值是表示对象的字符串。用的最多的是被其覆盖的Date.prototype.toLocaleString()
。具体代码如下:
var obj = {a:'1123aa'};
obj.toLocaleString();//"[object Object]"
-
toString()
:返回对象的字符串表示,其返回值是表示对象的字符串。具体代码如下:
var obj = {a:'1123aa'};
obj.toString();//"[object Object]"
可以通过Object.prototype.toString
去检测一个内置对象是属于什么类型。需要用到call
或者apply
,具体代码如下:
var toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
值得注意的是,一定是内置对象,如果是其他对象,统一返回[object object ]
.
-
valueOf()
:返回对象的原始值。具体代码如下:
var obj = {a:'1123aa'};
obj.valueOf();//Object {a: "1123aa"}
值得注意的是数据类型在做转换的时候,一般是先用valueOf()
转换,再用toString()
进行转换。但是如果是Date
类型的数据,是先用toString()
,再用valueOf()
。
object
自身的方法:
-
Object.assign(target,····source)
:该方法是ES6的方法,接受2‘个’参数,第一个参数是目标对象,第二个参数是多个参数,以逗号形式连接的‘源对象’。该方法是用于将所有可以枚举的属性的值从一个或者多个源对象复制到目标对象,并返回目标对象。
关于Object.assign()
,还有几点值得注意:
- 如果目标对象与源对象都有相同的属性,以源对象为准。如果源对象之间,有相同的属性,以源对象排在后面的为准。
- 如果在复制过程中,抛出错误,目标对象保持不变 。
-
Object.assign()
只复制自身的属性,不可枚举的属性(enumerable
为false
)和继承的属性不会被复制。 -
Symbol
也会被复制。 - 如果复制的属性本身是对象,那么进行浅拷贝,如果已有该属性,会被替换。
- 如果复制的属性本身是数组,那么会被视为属性名为0、1、2的对象来处理,具体如下:
Object.assign([1,2,3],[4,5])//[4, 5, 3]
- 只要参数中,有一个不是对象,就会报
TypeError
错误。
其具体代码如下:
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj1.a = 1;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj2.a = 2;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
//深拷贝
obj1 = { a: 0 , b: { c: 0}};
let obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}
-
Object.create(prototype,descriptors)
:该方法一共有2个参数,第一个参数为必选,是要用作原型的对象。可以为null
,如果是null
,会创建一个没有继承任何方法的对象,这个对象可以当做伪全局变量,存一些东西。第二个参数可选,包含一个或多个类似于Object.defineProperty()
函数的对象。
Object.create(prototype,descriptors)
具体用法太多,太杂,这里就不做深入了,也很难深入下去了,单独第一个参数还好,用于继承什么的。第二个参数就很复杂了,我觉得应该和开发底层框架有关吧,也许。关于Object.create(prototype,descriptors)
只包含第一个参数的例子,可以去我之前写过的《JavaScript 继承!我有话要说》看看。
-
Object.defineProperty(obj, prop, descriptor)
:该方法用于给对象上定义一个新属性,或者修改该对象上的现有属性,并返回该对象。此方法一共有3个参数,第一个参数期待一个对象,之后的操作都是基于这个对象的。第二个参数是需要定义或者修改的属性名。第三个参数是定义或者修改属性的描述符(descriptor)。
这个方法和一般直接定义属性有些不一样,或者说更加严格,规范一些。用在底层框架比较多。描述符里面有configurable
,enumerable
等等限定该属性功能,行为,值的属性描述符和数据描述符。如下代码:
var obj = {a : 2};
Object.getOwnPropertyDescriptor(obj,'a')//Object {value: 2, writable: true, enumerable: true, configurable: true}
可以看到,obj
的a
属性有4个描述符,其中一个是value
,是数据描述符。还有另外3个是,configurable
(可配置),enumerable
(可枚举),writable
(可写)。下面,我们来详细讲解一下这3个描述符。
-
writable
:决定了是否可以修改属性的值。具体代码如下:
var obj = {};
Object.defineProperty(obj,'a',{
value:2,
writable:false,//不可修改!
configurable:true,
enumerable:true,
})
obj.a = 3;//尝试修改
console.log(obj.a)//2
正如你所看到的,我们赋值3
失败了,因为这个属性被定为writable:fasle
不可写。如果在严格模式下,这样值,会报错TypeError
。
其实在我们定下writable:fasle
的时候,已经设定了一个空操作setter
,所以,要和writable:fasle
一致,需要将setter
调用时,抛出一个TypeError
错误。
-
configurable
:如果该属性是configurable:true
,就可以使用Object.defineProperty(··)
来修改描述符,代码如下:
var obj = {};
Object.defineProperty(obj,'a',{
value:2,
writable:true,
configurable:false,//不可配置!
enumerable:true,
})
obj.a = 3;
console.log(obj.a)//3
//尝试配置obj
Object.defineProperty(obj,'a',{
value:2,
writable:true,
configurable:true,
enumerable:true,
})//TypeError!
所以可以看出configurable:false
是单向的,不可逆的。还有两点,第一点,就算是configurable:false
,我们还可以修改writable:true
为false
,但是不能将false
变为true
。第二点,当configurable:false
时,此时的a
属性是无法delete
的。
-
enumerable
:决定了该属性是否可枚举。没什么说的,设置为false
,for in
循环无法遍历这个属性。
-
Object.defineProperties(obj, props)
:和Object.defineProperty(obj, prop, descriptor)
功能类似,只不过可以同时定义多个属性,具体如下:
var obj = {};
Object.defineProperties(obj, {
'a': {
value: true,
writable: true
},
'b': {
value: 'Hello',
writable: false
}
});
obj.a//true
-
Object.freeze(obj)
:该方法是用来冻结一个对象,也就是阻止添加新属性; 防止现有属性被删除; 并防止现有属性或其可枚举性,可配置性或可写性更改。该方法返回冻结状态下的对象。该方法期待一个为对象的参数。
其实这个方法相当于对当前对象调用Object.seal()
并且将所有的'数据访问'属性标记为writable:false
。 -
Object.seal(obj)
:该方法创建一个密封的对象,实际上是对该对象调用Object.preventExtensions(··)
并把所有现有属性标记为configurable:false
。 -
Object.preventExtensions(obj)
:如果你想禁止一个对象添加新属性并且保留自己的已有属性,就可以使用该方法。
var obj = {a:2};
Object.preventExtensions(obj);
obj.b = 3;
obj.b//undefined
-
Object.getOwnPropertyDescriptor(obj, prop)
:该方法接受2个参数,第一个参数是被查找属性的对象,第二个对象是查找的属性名,如果存在该属性,返回其属性描述符,如果不存在,返回undefined
。 -
Object.getOwnPropertyNames(obj)
:该方法返回一个给定对象的所有属性名(可枚举或不可列)的数组。代码如下:
var obj = { 0: 'a', 1: 'b', 2: 'c' };
Object.getOwnPropertyNames(obj);//["0", "1", "2"]
-
Object.getOwnPropertySymbols(obj)
:该方法返回一个给定对象的所有符号属性名的数组。代码如下:
var obj = {};
var a = Symbol('a');
var b = Symbol('b');
obj[a] = 'aaa';
obj[b] = 'bbb';
Object.getOwnPropertySymbols(obj);//[Symbol(a), Symbol(b)]
-
Object.getPrototypeOf(obj)
:该方法返回指定对象的原型prototype
。具体代码如下:
var str = '123';
Object.getPrototypeOf(str)//String.prototype
-
Object.is(value1,value2)
该方法接受2个参数,比较2个参数是否相等。与===
有一点不同,具体如下:
console.log(-0 === +0)//true
console.log(Object.is(-0,+0))//false
Object.is(value1,value2)
是要真的等,才返回true。
-
Object.isExtensible(obj)
,Object.isFrozen(obj)
,Object.isSealed(obj)
:分别是判断对象是否可扩展,是否被冻结,是否被密封,如果是,返回true
,如果不是,返回false
。 -
Object.key(obj)
可以理解为只返回自身的可枚举属性的for in
循环。具体代码如下:
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']