Object中一些常见的用法
1 Object.key()
在这里我们着重关注的是第一点 ,在我们学习中,用的比较多的也就第一种!
读取对象的所有属性。
(1).例如,传入一个对象,返回包含对象可枚举的属性
var obj = {
name: 'hanhan',
age: 22,
say: function() {
console.log("Hello World");
}
}
console.log(Object.keys(obj));
打印结果:
Object.keys()的结果为一个数组,值为里面的属性,通常我们在对象里面的函数称之为方法 ,obj里面的say方法
(2).例如,传入一个字符串,返回字符串索引值
var Str="Hello World"
console.log(Object.keys(Str));
打印得到:
在这里要注意的一点是其中的空格也是算进去了 所以返回了11个索引组成的数组
(3)例如,传入一个数组,返回索引值
var arr=['a','b','c'];
console.log(Object.keys(arr));
打印得到:
依旧是索引组成的数组
2 Object.values()
这个方法也是用的比较多的!
方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用for…in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。
语法:
Object.values(obj)
参数:
obj:被返回可枚举属性值的对象。
返回值:
一个包含对象自身的所有可枚举属性值的数组。
描述:
Object.values()返回一个数组,其元素是在对象上找到的可枚举属性值。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。
var obj = {
name: "hanhan",
color: "#58bc58",
age: 22
};
console.log(Object.values(obj));
打印得到:
这里是得到属性值组成的一个数组
3 Object.assign()
该方法用于将所有可枚举属性的值从一个或多个对象复制到目标对象。它将返回目标对象。
语法:
Object.assign(target,…sources)
参数说明:
target:目标对象。
…sources:源对象。
返回值:
目标对象。
var a = {
name: "hanhan",
age: 22,
color: "#58bc58"
};
var c = Object.assign({ address: "beijing" }, a);
console.log(c);
console.log(a);
打印得到:
Object.assign并不会改变源对象,但是会改变目标对象
var a = {
name: "hanhan",
age: 22,
color: "#58bc58"
};
var b={
job:"teacher"
}
var c = Object.assign(b, a);
console.log(b);
打印得到:
上述例子中b的结果被改变了。
注意点:
如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖。后来的源的属性将类似地覆盖早先的属性。
Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()和Object.defineProperty() 。
在出现错误的情况下,例如,如果属性不可写,会引发TypeError,如果在引发错误之前添加了任何属性,则可以更改target对象。
注意,Object.assign 不会跳过那些值为 null 或 undefined 的源对象。
4 Object.entries()
语法:
Object.entries(obj)
参数:
obj:可以返回其可枚举属性的键值对的对象。
返回值:
给定对象自身可枚举属性的键值对数组。注意:返回的是一个数组。
描述:
Object.entries()返回一个数组,其元素是与直接在object上找到的可枚举属性键值对相对应的数组。属性的顺序与通过手动循环对象的属性值所给出的顺序相同。
Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环也枚举原型链中的属性)。
const obj1 = { name: "hanhan", age: 22, color: "#58bc58" };
console.log(Object.entries(obj1));
打印得到:
5 Object.getPrototypeOf()
该方法返回参数对象的原型,这是获取原型对象的标准方法。
var F=function(){}
var f=new F();
console.log(Object.getPrototypeOf(f)===F.prototype);
//结果为true
解释:上面代码中,实例对象f的原型是F.prototype
下面几种特殊对象的原型:
// 空对象的原型是Object.prototype
console.log(Object.getPrototypeOf({})===Object.prototype);
//结果为true
//Object.prototype的原型是null
console.log(Object.getPrototypeOf(Object.prototype)===null);
// 结果为true
//函数的原型是Function.prototype
function f(){}
console.log(Object.getPrototypeOf(f)===Function.prototype);
//结果为true
6 Object.setPrototypeOf()
该方法为参数对象设置原型,返回该参数对象,它接受2个参数,第一个是现有对象,第二个是原型对象。
var a={age:22};
var b={name:'hanhan'};
var c=Object.setPrototypeOf(a,b);//设置b为a的原型对象
console.log(c);//结果为{age:22},返回第一个参数的对象
console.log(Object.getPrototypeOf(a)===b);//结果为true
console.log(a.name);//结果为'hanhan',此时对象a可以直接调用对象b中的属性
注释:上面代码中Object.setPrototypeOf方法将对象a的原型设置为对象b,因此a可以共享b的属性。
new命令可以使用Object.setPrototypeOf方法模拟如下:
var F = function() {
this.foo = "bar";
}
var f = new F();
//等同于
var f = Object.setPrototypeOf({}, F.prototype);
F.call(f);
console.log(f)
上面代码中,new命令新建实例对象,其实可以分成两步。1.将一个空对象的原型设为构造函数的prototype属性(上例是F.prototype),2.将构造函数内部的this绑定这个空对象,然后执行构造函数,使得定义在this上面的方法和属性(上例是this.foo),都转移到这个空对象上。
7 Object.create()
生成实例对象的常用方法,使用new命令让构造函数返回一个实例,但是很多时候,只能拿到一个实例对象,它可能根本不是由构造函数生成的,那么能不能从一个实例对象,生成另一个实例对象呢?
js提供了Object.create()方法,来满足这种需求,该方法接受一个对象作为参数,然后以它为原型,返回一个实例对象,该实例完全继承原型对象的属性。
var A = {
say: function() {
console.log("我说点啥?")
}
}
//使用A作为B的原型,此时B将会拥有A的属性和方法
var B = Object.create(A);
//判断B的原型对象是不是A
console.log(Object.getPrototypeOf(B) === A); //结果为true
//B可以直接调用A的方法
B.say(); //结果为”我说点啥?“
//判断A和B的方法是不是同一个?
console.log(B.say === A.say); //结果为true
上面代码中,Object.create方法以A对象为原型,生成了B对象,B继承了A的所有属性和方法。
使用Object.create方法的时候,必须提供对象原型,即参数不能为空,或者不是对象,否则会报错。
如下会报错:
Object.create();
Object.create(123)
Object.create方法生成的新对象,动态继承了原型。在原型上添加或修改任何方法,会立刻反映在新对象之上。
var obj1 = {
p: 1
};
var obj2 = Object.create(obj1);
obj1.p = 2;//修改obj1的p属性的值
console.log(obj2.p);//打印结果为2
上面代码中,obj2继承obj1,修改obj1会影响到obj2
除了对象的原型,Object.create方法还可以接受第二个参数,该参数是一个属性描述对象,它所描述的对象属性,会添加到实例对象,作为该对象自身的属性。
var obj = Object.create({}, {
p1: {
value:123,
enumerable:true,
configurable:true,
writable:true
},
p2:{
value:'hello',
enumerable:true,
configurable:true,
writable:true
}
});
//等同于
var obj = Object.create({});
obj.p1 = 123;
obj.p2 = 'hello';
Object.create方法生成的对象,继承了它的原型对象的构造函数。
function A() {}
var a = new A();
var b = Object.create(a);
b.constructor === A // true
b instanceof A // true
上面代码中,b对象的原型是a对象,因此继承了a对象的构造函数A。
8 Object.freeze()
Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。该方法返回被冻结的对象。
语法:
Object.freeze(obj)
参数:
obj:要被冻结的对象
返回值:
被冻结的对象。
描述:
被冻结对象自身的所有属性都不可能以任何方式被修改。任何修改尝试都会失败,无论是静默地还是通过抛出TypeError异常(最常见但不仅限于strict mode)。
数据属性的值不可更改,访问器属性(有getter和setter)也同样(但由于是函数调用,给人的错觉是还是可以修改这个属性)。如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。数组作为一种对象,被冻结,其元素不能被修改。没有数组元素可以被添加或移除。
这个方法返回传递的对象,而不是创建一个被冻结的副本。
const obj1 = { name: "hanhan", age: 22, color: "#58bc58" };
Object.freeze(obj1);//冻结obj1
obj1.name="coco";
delete obj1.age;
obj1.adress="beijing";
console.log(obj1);
打印得到:
因为里面属性被冻结不能修改 所以输出还是原来的对象
9 Object.prototype.isPrototypeOf()
实例对象的isPrototypeOf方法,用来判断该对象是否为参数对象的原型。
//创建一个空对象m1
var m1 = {}
//创建一个对象m2,使用m1作为m2的原型
var m2 = Object.create(m1);
//创建一个m3,使用m2作为m3的原型
var m3=Object.create(m2);
//使用isPrototypeOf来判断m2是否为m3的原型
console.log(m2.isPrototypeOf(m3));//结果为true
//使用isPrototypeOf来判断m1是否为m3的原型
console.log(m1.isPrototypeOf(m3));//结果为true
上面代码中m1和m2都是m3的原型,这表明只要实例对象处在参数对象的原型链上,isPrototypeOf方法都返回true.
10 Object.prototype. _ _ proto_ _
实例对象的__proto__属性(前后各两个下划线),返回该对象的原型。该属性可读写。
var obj = {};
var p = {};
obj.__proto__ = p;
Object.getPrototypeOf(obj) === p // true
上面代码通过__proto__属性,将p对象设为obj对象的原型。
根据语言标准,__proto__属性只有浏览器才需要部署,其他环境可以没有这个属性。它前后的两根下划线,表明它本质是一个内部属性,不应该对使用者暴露。因此,应该尽量少用这个属性,而是用Object.getPrototypeof()和Object.setPrototypeOf(),进行原型对象的读写操作。
原型链可以用__proto__很直观地表示。
var A = {
name: '张三'
};
var B = {
name: '李四'
};
var proto = {
print: function () {
console.log(this.name);
}
};
A.__proto__ = proto;
B.__proto__ = proto;
A.print() // 张三
B.print() // 李四
A.print === B.print // true
A.print === proto.print // true
B.print === proto.print // true
上面代码中,A对象和B对象的原型都是proto对象,它们都共享proto对象的print方法。也就是说,A和B的print方法,都是在调用proto对象的print方法。
如上所述,__proto__属性指向当前对象的原型对象,即构造函数的prototype属性。
//创建一个构造函数
var obj = function() {
this.name = 'hanhan';
}
//实例化一个对象
var m1 = new obj();
// 判断实例对象m1的__proto__是否是构造函数的prototype
console.log(m1.__proto__ === obj.prototype); //结果为true
//判断实例对象m1的__proto__是否是当前构造函数的属性,m1.constructor.prototype
console.log(m1.__proto__ === m1.constructor.prototype); //结果为true
上面的代码首先创建了一个m1实例对象,它的__proto__属性,指向构造函数(obj或m1.constructor)的prototype属性。因此,获取实例对象m1的原型对象,有三中方法:
(1)m1.proto
(2)m1.constructor.prototype
(3)Object.getPrototypeOf(m1);
上面三种方法之中,前两种都不是很可靠。__proto__属性只有浏览器才需要部署,其他环境可以不部署。而m1.constructor.prototype在手动改变原型对象时,可能会失效。推荐使用第三种Object.getPrototypeOf方法,获取原型对象。
11 Object.getOwnPropertyNames()
该方法返回一个数组,成员是参数对象本身的所有属性的键名,不包含继承的属性键名。
console.log(Object.getOwnPropertyNames(Date));
//结果为 ["length", "name", "prototype", "now", "parse", "UT
上面代码中,Object.getOwnPropertyNames方法返回Date所有自身的属性名。
对象本身的属性之中,有的是可以遍历的(enumerable),有的是不可以遍历的。Object.getOwnPropertyNames方法返回所有键名,不管是否可以遍历。只获取那些可以遍历的属性,使用Object.keys方法。
Object.keys(Date) //结果为一个空数组 []
上面代码表明,Date对象所有自身的属性,都是不可以遍历的。
12 Object.prototype.hasOwnProperty()
对象实例的hasOwnProperty方法返回一个布尔值,用于判断某个属性定义在对象自身,还是定义在原型链上。
Date.hasOwnProperty('length') // true
Date.hasOwnProperty('toString') // false
上面代码表明,Date.length(构造函数Date可以接受多少个参数)是Date自身的属性,Date.toString是继承的属性。另外,hasOwnProperty方法是 JavaScript 之中唯一一个处理对象属性时,不会遍历原型链的方法。
对象中的数据属性(数据描述符)
数据属性有4个描述内部属性的特性:
(1)configurable
定义:表示能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使用字面量定义对象,默认值为true
var person = {}
Object.defineProperty(person, 'name', {
configurable: false,
value: 'hanhan'
})
delete person.name; //会报错,configurable为false不能删除
(2)enumerable
定义:表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使用字面量定义对象,默认值为true
(3)writable
定义:能否修改属性的值,如果直接使用字面量定义对象,默认值为true
(4)value
定义:该属性对应的值,默认为undefined
访问器属性(存取描述符)
访问器属性也有4个描述内部属性的特性
(1)configurable
定义:和数据属性的[[Configurable]]一样,表示能否通过delete删除此属性,能否修改属性的特性,或能否修改把属性修改为访问器属性,如果直接使用字面量定义对象,默认值为true
(2)enumerable
定义:和数据属性的[[Configurable]]一样,表示该属性是否可枚举,即是否通过for-in循环或Object.keys()返回属性,如果直接使用字面量定义对象,默认值为true
(3)get
定义:一个给属性提供 getter 的方法(访问对象属性时调用的函数,返回值就是当前属性的值),如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为 undefined
(4)set
定义:一个给属性提供 setter 的方法(给对象属性设置值时调用的函数),如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为 undefined
13 Object.defineProperty()
功能:
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。如果不指定configurable, writable, enumerable ,则这些属性默认值为false,如果不指定value, get, set,则这些属性默认值为undefined
语法:
Object.defineProperty(obj, prop, descriptor)
参数说明:
obj: 需要被操作的目标对象
prop: 目标对象需要定义或修改的属性的名称
descriptor: 将被定义或修改的属性的描述符
代码如下:
//定义一个名为obj对象
var obj = new Object();
//为对象obj定义一个属性名为name,然后对name进行描述
Object.defineProperty(obj, 'name', {
configurable: false, //能否通过delete删除name属性,能否修改属性的特性,能否修改把属性修改为访问器属性
writable: true, //能否修改属性的值
enumerable: true, //该属性是否可枚举,即是否通过for...in循环或Object.keys()返回属性
value: 'hanhan' //该属性对应的值
})
console.log(obj.name);
14 Object.defineProperties()
功能:
方法直接在一个对象上定义一个或多个新的属性或修改现有属性,并返回该对象。
语法:
Object.defineProperties(obj, props)
参数说明:
obj: 将要被添加属性或修改属性的对象
props: 该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置
var obj = new Object();
Object.defineProperties(obj, {
name: {
value: '张三',
configurable: false,
writable: true,
enumerable: true
},
age: {
value: 18,
configurable: true
}
})
console.log(obj.name, obj.age) // 张三, 18
15 Object.getOwnPropertyDescriptor()
功能:
该方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性),即返回对象的属性描述。
语法:
Object.getOwnPropertyDescriptor(obj, prop)
参数说明:
obj: 需要查找的目标对象
prop: 目标对象内属性名称
var person = {
name: '张三',
age: 12
}
var des = Object.getOwnPropertyDescriptor(person, 'name');
console.log(des);
// 结果如下:{value: "张三", writable: true, enumerable: true, configurable: true}
16 Object.getOwnPropertyDescriptors()
功能:
所指定对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。
语法:
Object.getOwnPropertyDescriptors(obj)
参数说明:
obj: 需要查找的目标对象
var person = {
name: '张三',
age: 12
}
var des = Object.getOwnPropertyDescriptors(person);
console.log(des);
// 结果如下:
// {
// name: {
// configurable: true
// enumerable: true
// value: "张三"
// writable: true
// },
// age: {
// configurable: true
// enumerable: true
// value: 12
// writable: true
// }
// }
在对象中添加存取描述符属性
// 定义一个对象obj
var obj = {}
// 定义一个变量a
var a = 1;
// 定义一个变量b
var b;
//为obj对象设置一个m属性
Object.defineProperty(obj, 'm', {
configurable: true,
enumerable: true,
//添加存取属性,当读取属性值时,调用get方法
get: function() {
return a + 1;
},
//当设置属性时,调用set方法
set: function(i) {
a = i + 2;
b = i + 1;
}
})
console.log(obj.m); //调用属性的get方法,结果为2
//为属性从新设置一个值,此时会调用set方法
obj.m = 4; //参数i的值就是4
console.log(a); //打印结果为6,a=i+2;i的值是4,所以a=6
console.log(b); //打印结果为5,b=i+1;i的值是4,所以b=5
注意:
1.getter和setter可以不同时使用,但在严格模式下只其中一个,会抛出错误
2.数据描述符与存取描述符不可混用,会抛出错误
value不能和get和set同时使用。
var obj = {}
var a = 1;
var b;
Object.defineProperty(obj, 'm', {
value:'123',//切记不能使用value和get,set同时使用,会报错
get: function() {
return a;
},
set: function(i) {
b = i + 1;
}
})
详细解读set和get访问器
set是给属性赋值,get是取属性的值,get是得到 一般是要返回的 set 是设置 不用返回
// 定义一个函数person
function person() {
// 定义一个变量age,值为18
var age = 18;
// 为当前函数定义一个personAge属性
Object.defineProperty(this, "personAge", {
//为其设置一个get访问器,当读取该属性时调用get
get: function() {
return age - 10;
},
//为其设置一个set访问器,当更新该属性时调用set
set: function(v) {
age = v;
}
})
}
//实例化person对象
var p = new person();
//读取personAge的值,此时会调用get中的方法
console.log(p.personAge); //打印结果为8
//重新为属性personAge设置一个值,此时会调用set中的方法
p.personAge = 1994;
console.log(p.personAge); //打印结果为1984
上一篇: HTML 中一些常用的标签
下一篇: Spring2.5 注释驱动的IoC功能