属性的简写方法
var name = '秦司令';
var json = {name} // name:'秦司令'
上面代码中,变量在对象中当做属性名,属性值就是变量的值,这就是属性的简写方式。
var age = 19
var obj = {
name:'秦司令',
age
}
console.log(obj) // {name:'秦司令',age:19}
函数中的声明的对象也能简写
function example(x,y){
return {x,y}
}
console.log(example(1,2)) // {x:1,y:2}
上面代码如果不传参,x和y的参数就是undefined。
对象里面的函数也可以简写。
var json = {
add(){
alert(1)
}
}
// 上面的方法等同于下面
var json = {
add:function(){
alert(1)
}
}
简写一个Generator函数,前面需要要加上 * 号
var obj = {
* add(){
yiled 'hello word'
}
}
上面代码中,Generator函数等下一期跟你们分享,详细讲解。
属性名表达式
js定义对象有两种方式
var obj = {}
obj.name = '秦司令';
obj['a' + 'ge'] = 19;
上面代码中,方法一是用标识符作为对象属性名,方法二是用表达式作为属性名,这是将表达式方在中括号内,中括号内可以写变量,请看下面代码。
let age = 'age';
var json = {
[age] :19,
['a' + 'bc'] : 123
}
console.log(json) // {age:19,abc:123}
表达式还可以用于定义方法名。
var obj = {
['a' + 'bc'](){
return 'abc'
}
}
console.log(obj.abc()) // abc
注意,对象的简写不能和表达式一起使用,会报错。
var name = '秦司令';
console.log({ [name] }) // 报错
console.log({ [name] : 123 }) // 秦司令:123
如果属性表达式是一个对象的话,默认情况下会自动转为字符串,[object Object] 。
var dx = {}
var json = {
[dx]:123
}
console.log(json) // {[object Object] :123}
方法name的属性
函数的name属性,返回函数名,对象方法也是函数,因此也有name属性。
var obj = {
add(){
return 123
}
}
console.log(obj.add.name) // add
上面代码,方法add的name属性就是函数名,add。
函数name属性有两种特殊情况,bind方法创造的函数,name属性返回 bound 加上函数名 ;Function 构造函数创造的函数,name属性返回anonymous 英语意思为(匿名的)
(new Function()).name // anonymous
function abc(){}
console.log(abc.bind().name) // bound abc
如果对象方法是一个Symbol值,那么name属性返回的就是这个Symbol值的描述。
var s = Symbol('foo')
var s1 = Symbol()
let obj = {
[s](){},
[s1](){}
}
console.log(obj[s].name) // ['foo']
console.log(obj[s1].name) // ""
上面代码中,s对应的Symbol值有描述,s1没有
属性的可枚举性和遍历
可枚举性
对象的每个属性都有一个描述对象(Descriptor),用来控制该属性的行为。
Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。
let obj = {foo:123};
Object.getOwnPropertyDescriptor(obj,'foo');
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
描述对象的enumerable属性称为 "可枚举性" , 如果该属性为false,就表示某些操作会忽略当前属性。
目前,有四种操作会忽略enumerable为false属性
for..in循环:只遍历对象自身和继承的可枚举性的属性
Object.keys() : 返回对象自身的所有可枚举属性的键名
JSON.stringify() : 只转换自身的可枚举性的属性
Object.assign() : 忽略enumerable为false的属性,只拷贝对象自身的可枚举性的属性
var json1 = {name:'秦司令'}
Object.defineProperty(json1,'age',{
value:19,
enumeable:false
})
for(var i in json1){
console.log(i) // name
};
console.log(Object.keys(json1)) // ['name']
console.log(JSON.stringify(json1)) // {"name":"秦司令"}
console.log(Object.assign({},json1)) // {name: "秦司令"}
上面代码中,都获取不到enumerable为false的属性,Object.defineProperty是专门设置描述对象的属性;
属性的遍历
Object.getOwnPropertyNames(obj)
该方法返回一个数组,包含自身的所有属性(不包含Symbol属性,但是包括不可枚举属性)的键名
var json1 = {name:'秦司令'}
Object.defineProperty(json1,'age',{
value:19,
enumeable:false
})
console.log(Object.getOwnPropertyNames(json1)) // ["name", "age"]
Object.getOwnPropertySymbols(obj)
该方法返回一个数组,包含对象自身的所有 Symbol 属性的键名,只返回Symbol的键名。
var jsonArr = {[Symbol('123')]:1,b:2,c:9,3:'d',[Symbol()]:123}
console.log(Object.getOwnPropertySymbols(jsonArr)) // [Symbol(123), Symbol()]
Reflect.ownKeys(obj)
该方法返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
var jsonArr = {[Symbol('123')]:1,b:2,c:9,3:'d',[Symbol()]:123}
console.log(Reflect.ownKeys(jsonArr)) // ["3", "b", "c", Symbol()]
上面代码中,Reflect.ownKeys该方法返回一个数组,返回所有的属性,这个数组的顺序是这样的,首先是数值属性,然后是字符串,按照字符串的位置加入,最后是Symbol属性
super关键字
Object.prototype.name = 'lider'
var json = {
name:'我是json',
add(){
return super.name;
}
}
console.log(json.add());
上面代码中,super该方法是指向Object的原型。
看下面的列子
var obj = {
name:'我是obj',
na(){
console.log(this.name)
}
}
var json = {
name:'我是json',
add(){
return super.name;
}
}
Object.setPrototypeOf(json,obj)
console.log(json.add()); // 我是obj
上面的代码,把json的原型改成了obj的原型,所以name属性就指向obj里面的。
super该方法现正只能,用在对象的简写方法内容。
// 报错
const obj = {
foo: super.foo
}
// 报错
const obj = {
foo: () => super.foo
}
// 报错
const obj = {
foo: function () {
return super.foo
}
}
对象的扩展运算符
Es2018将扩展运算符引入了对象。
var [a...b] = [1,2,3]
a //1
b // 2 3
解构赋值
对象的解构赋值用于从一个对象取值,相当于将目标对象自身所有可遍历属性(包括enumerable),但尚未被读取的属性,分配到指定的对象上面,所有的键和它们的值,都会拷贝到新对象上面。
let {x,y...z} = {x:1,y:2,c:3,d:4}
x // 1
y // 2
z // {c:3,d:4}
上面代码中,变量z是解构赋值所在的对象,它获取等号右边尚未读取的值,并且将(键值和属性值) 一同拷贝过来
解构赋值要求等号右边必须是对象,如果不是对象,就会强制转换为对象,undefined和null无法转换为对象,所以它们会报错。
let {...z} = null;
let {...a} = undefined
解构赋值必须最后一个参数是扩展运算符,否则会报错。
let {...a,b} = {a:1,b:2}
注意,解构赋值的拷贝是浅拷贝,即如果一个键值的是数组或者是对象,那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2
另外,扩展运算符的解构赋值,不能复制继承的原型。
let o1 = { a: 1 };
let o2 = { b: 2 };
o2.__proto__ = o1;
let { ...o3 } = o2;
o3 // { b: 2 }
o3.a // undefined
如果扩展运算符后面是一个对象,则没有任何效果。
console.log( {...{} , a:123 } ) // {a:123}
如果扩展运算符后面不是对象,则会自动将其转为对象。
console.log({...1}) // {}
上面代码中,将其转换为对象 包装类Number{1} ,因此它没有属性则返回空对象。
如果扩展运算符后面是字符串,它会自动转成一个类似数组的对象,因此返回的不是空对象。
{...'hello'}
// {0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}
扩展运算符的参数之中,如有取值函数get,这个函数是会执行的。
let abc = {
get aa(){
return 1
}
}
console.log(abc)
let abc1 = {
...{
get aa(){
return '我自动执行'
}
}
}
console.log(abc1)