对象的扩展
写在前面的话
感觉博客写的有点太细了,导致我学习进度过于缓慢。
因此,建议学习者以阮一峰博客为主,以本博客为补充。
我这里主要写一些示例和补充,帮助理解的更为全面
0、一句话总结
- 属性名,以及是属性的函数的简洁写法,写起来简单易阅读
- 属性名可以用变量字符串拼接起来(话说以前也有吧?)
- 函数都有name属性,但set和get也要加前缀
- Object.is判断两个变量是否相等
- Object.assign可以合并对象的非原型链上,且可枚举属性
- Object.getOwnPropertyDescriptor查看属性是否可枚举、可修改、可赋值
- Object.keys获取对象非原型链上,且可枚举属性的key
- Object.values获取对象非原型链上,且可枚举属性的值
- Object.entries同时获取上面两个
- 当属性在原型链上,或者不可枚举时,会被很多方法忽视(参照6.1)
- __proto__和prototype的关系(参照7.1)
- Object.setPrototypeOf(obj, prototype)设置__proto__属性
- Object.getPrototypeOf(obj)获取__proto__属性
- es7新增对对象有效的扩展运算符…(三个点)
本篇没有的请翻看【对象的扩展】系列的其他篇
1、简洁写法(缩写)
1.1、属性名缩写,与函数的缩写
属性名的缩写
var foo = "abc";
var test = [];
var bar = {
foo, test
}
//相当于
var bar = {
foo: foo,
test: test
}
函数缩写
var foo = {
fun(a, b){
}
}
//相当于
var foo = {
fun: function (a, b) {
}
}
因为缩写的属性名会总理解为字符串,所以,据说不会因为关键词而报错?(但我的chrome实测用关键词class作为key也不会报错啊)
但,一个合格的程序员,不要去用关键词去做key,这可以避免很多本来不应该发生的bug。
1.2、错误的缩写
var p(){
console.log("p")
}
以上这种缩写就不行,函数只有在作为属性的key时才能这么写。
1.3、setter和getter的简洁写法
讲真的!setter和getter用简洁写法写起来超级舒服啊!用正常写法超级麻烦,见代码:
简洁写法:
//简洁写法
var cart = {
_wheels: 4,
get wheels() {
return this._wheels;
},
set wheels(value) {
if (value < this._wheels) {
throw new Error('数值太小了!');
}
this._wheels = value;
}
}
正常写法:
var cart = {
_wheels: 4
}
Object.defineProperty(cart, "wheels", {
get: function () {
return this._wheels;
},
set: function (value) {
if (value < this._wheels) {
throw new Error('数值太小了!');
}
this._wheels = value;
}
});
友情提示:
想把简洁写法用非正常写法来实现的,都是不可能的,我自己测试来看,以下写法都不行
//以下都不行
var cart = {
_wheels: 4,
wheels: {
get() {
return this._wheels;
}
}
}
var cart = {
_wheels: 4,
wheels: function get() {
return this._wheels;
}
}
2、属性名表达式
2.1、可以的写法
字符串变量可以作为key,并且作为key时也可以通过表达式来拼接。
let foo = {
//字符串作为key
["test"] () {
console.log("test");
},
//一般用于key名拼接
["b" + "ar"](){
console.log("bar");
}
}
比较特殊的是,因为属性名是字符串,因此只要符合字符串格式的都可以作为key,但是获取该属性的值时,也只能通过字符串的形式来获取。
比较典型的就是属性名中间有空格这种情况。
2.2、不可以的写法
不能既用简洁写法,又用字符串变量作为key。
原因是简洁写法是将变量名作为变量在对象中的属性名;
而用字符串变量作为key的简洁写法,和简洁写法的原意相反,是用 变量的值 作为 属性名,显然是不可以的。
而且也只有属性名,没有值。
let foo = "test";
let bar = {
[foo]
};
//bar的可能
let bar = {
["test"]: ? //只有key没有值
}
2.3、不要用对象作为属性的key
原因是会被toString隐式转换为字符串,如示例:
···
var foo = {
toString(){
return “test foo”
}
};
var bar = {
[foo]: “bar”
}
bar[“test foo”] === “bar”; //true
···
默认情况下,隐式转换后的结果为:字符串 "[object Object]"
3、方法的name属性
3.1、普通写法的
跟之前函数的name属性的获取没啥区别,即使他是简写。如代码:
var foo = {
bar(){}
}
foo.bar.name; //"bar",函数名
3.2、想要获取setter和getter的
话说获取这个有必要么?
setter和getter一般是变量,又不是函数,有必要获取他的名字么?不明白。
获取方法的话,先要通过API拿去它的属性描述符。
Object.getOwnPropertyDescriptor(obj, key)
以上方法返回一个对象,描述obj对象的属性key的属性,比如是否可编辑啊,是否可枚举啊之类(具体可能视属性有所不同);
var cart = {
_wheels: 4,
get wheels() {
return this._wheels;
},
set wheels(value) {
if (value < this._wheels) {
throw new Error('数值太小了!');
}
this._wheels = value;
}
}
var returnObject = Object.getOwnPropertyDescriptor(cart, "wheels");
//Object {enumerable: true, configurable: true, get: function, set: function}
returnObject.set.name; //"set wheels"
returnObject.get.name; //"get wheels"
之所以能做到。首先是因为获取到了一个对象,而这个对象有set和get两个函数,而函数是可以获取到name属性的,又因为是set和get,所以name属性要加前缀”set”和”get”,就像bind绑定的函数里,前缀有”bound”一样。
除了以上三种前缀,匿名函数是name是”anonymous”。
除此之外还有Symbol,其name不同,不过我还没看,略略略。