ES6对象扩展
属性表示
ES6 允许在对象之中,直接写变量。这时,属性名为变量名, 属性值为变量的值。
function f(x, y) {
return {x, y};
}
// 等同于
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
属性名表达式
// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
表达式作为属性名要写在方括号中。
如果属性名表达式是一个对象,会转为字符串[object Object]
。
const keyA = {a: 1};
const keyB = {b: 2};
const myObject = {
};
myObject // Object {[object Object]: "valueB"}
[keyA]
和[keyB]
得到的都是[object Object]
,所以[keyB]
会把[keyA]
覆盖掉,而myObject
最后只有一个[object Object]
属性。
Object.is()
它用来比较两个值是否严格相等,与严格比较运算符(===
)的行为基本一致。
不同之处:
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
Object.assign()
Object.assign
方法用于对象的合并,将源对象(source
)的所有可枚举属性,复制到目标对象(target
)。
var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
同名的情况下,后者覆盖前者。
Object.assign(undefined) // 报错
Object.assign(null) // 报错
let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
首参不能为undefined
或null
,两者不能转换成对象。在其他位置,会给自动忽略掉。 数值和布尔值都会被忽略,字符串会以数组形式传入。
注意:
Object.assign()
是浅拷贝,原对象改变,它也会改变。
var obj1 = {a: {b: 1}};
var obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
属性描述符
属性描述符有两种主要形式:数据描述符
和存取描述符
。
存取描述符
是由一对 getter-setter
函数功能来描述的属性。
描述符必须是两种形式之一
,不能同时是两者。
数据描述符
下列的属性在Object.defineProperty
中默认为false
,但在基本的对象数据结构中,下列属性默认为true
。
是否可以删除目标属性或是否可以再次修改属性的特性(writable
, configurable
, enumerable
)。默认为 false。
此属性是否可以被枚举(使用for...in
或Object.keys()
)。设置为true
可以被枚举;设置为false
,不能被枚举。默认为false。
属性的值是否可以被重写。设置为true
可以被重写;设置为false
,不能被重写。默认为false。
属性对应的值,可以使任意类型的值,默认为undefined。
var obj = {
test:"hello"
}
//对象已有的属性添加特性描述
Object.defineProperty(obj,"test",{
configurable:true | false,
enumerable:true | false,
value:任意类型的值,
writable:true | false
});
//对象新添加的属性的特性描述
Object.defineProperty(obj,"newKey",{
configurable:true | false,
enumerable:true | false,
value:任意类型的值,
writable:true | false
});
查看设置:
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
// {
// value: 123,
// writable: true,
// enumerable: true,
// configurable: true
// }
ES5有三个操作会忽略enumerable
为false
的属性。
for...in循环:只遍历对象自身的和继承的可枚举的属性
Object.keys():返回对象自身的所有可枚举的属性的键名
JSON.stringify():只串行化对象自身的可枚举的属性
ES6新增了一个操作Object.assign()
,会忽略enumerable
为false
的属性,只拷贝对象自身的可枚举的属性。
Object.getOwnPropertyDescriptor(Object.prototype, 'toString').enumerable
// false
Object.getOwnPropertyDescriptor([], 'length').enumerable
// false
toString
和length
属性的enumerable
都是false
,因此for...in
不会遍历到这两个继承自原型的属性。
存取器描述
当使用存取器描述属性的特性的时候,允许设置以下特性属性:
var obj = {};
Object.defineProperty(obj,"newKey",{
get:function (){} | undefined,
set:function (value){} | undefined
configurable: true | false
enumerable: true | false
});
当使用了getter或setter方法,不允许使用writable和value这两个属性。
var obj = {};
var initValue = 'hello';
Object.defineProperty(obj,"newKey",{
get:function (){
//当获取值的时候触发的函数
return initValue;
},
set:function (value){
//当设置值的时候触发的函数,设置的新值通过参数value拿到
initValue = value;
}
});
//获取值
console.log( obj.newKey ); //hello
//设置值
obj.newKey = 'change value';
console.log( obj.newKey ); //change value
参考:
属性的遍历
for...in
for...in
循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
Object.keys(obj)
Object.keys
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)。
Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames
返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)。
Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols
返回一个数组,包含对象自身的所有Symbol属性。
Reflect.ownKeys(obj)
Reflect.ownKeys
返回一个数组,包含对象自身的所有属性,不管是属性名是Symbol或字符串,也不管是否可枚举。
__proto__属性
__proto__
属性(前后各两个下划线),用来读取或设置当前对象的prototype
对象。
// es6的写法
var obj = {
method: function() { ... }
};
obj.__proto__ = someOtherObj;
// es5的写法
var obj = Object.create(someOtherObj);
obj.method = function() { ... };
Object.defineProperty()
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
Object.setPrototypeOf()
Object.setPrototypeOf
方法的作用与__proto__
相同,用来设置一个对象的prototype
对象。
// 格式
Object.setPrototypeOf(object, prototype)
// 用法
var o = Object.setPrototypeOf({}, null);
//该方法等同于下面的函数。
function (obj, proto) {
obj.__proto__ = proto;
return obj;
}
Object.getPrototypeOf()
该方法与setPrototypeOf
方法配套,用于读取一个对象的prototype
对象。
Object.getPrototypeOf(obj);
//下面是一个例子。
function Rectangle() {
}
var rec = new Rectangle();
Object.getPrototypeOf(rec) === Rectangle.prototype
// true
Object.setPrototypeOf(rec, Object.prototype);
Object.getPrototypeOf(rec) === Rectangle.prototype
// false
Object.keys(),Object.values(),Object.entries()
Object.keys
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
Object.values
该方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable
)属性的键值。
Object.entries
该方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable
)属性的键值对数组。
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
对象的扩展运算符
解构赋值
对象的解构赋值用于从一个对象取值,相当于将所有可遍历的、但尚未被读取的属性,分配到指定的对象上面。所有的键和它们的值,都会拷贝到新对象上面。
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
上面代码中,变量z
是解构赋值所在的对象。它获取等号右边的所有尚未读取的键(a
和b
),将它们连同值一起拷贝过来。
扩展运算符
扩展运算符(...
)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中。
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
这等同于使用Object.assign
方法。
let aWithOverrides = { ...a, x: 1, y: 2 };
// 等同于
let aWithOverrides = { ...a, ...{ x: 1, y: 2 } };
// 等同于
let x = 1, y = 2, aWithOverrides = { ...a, x, y };
// 等同于
let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });
Object.getOwnPropertyDescriptor()
返回某个对象属性的描述对象(descriptor
)。
var obj = { p: 'a' };
Object.getOwnPropertyDescriptor(obj, 'p')
// Object { value: "a",
// writable: true,
// enumerable: true,
// configurable: true
// }
Object.create(prototype, descriptors)
创建一个具有指定原型且可选择性地包含指定属性的对象。
descriptors
可选。 包含一个或多个属性描述符的 JavaScript 对象。
var newObj = Object.create(null, {
size: {
value: "large",
enumerable: true
},
shape: {
value: "round",
enumerable: true
}
});
document.write(newObj.size + "<br/>");
document.write(newObj.shape + "<br/>");
document.write(Object.getPrototypeOf(newObj));
// Output:
// large
// round
// null
JS原型和原型链
每个构造函数生成实例的时候 会自带一个constructor属性 指向该构造函数
//所以:
实例.constructor == 构造函数
var arr = new Array();
arr.constructor === Array; //true
arr instanceof Array; //true
每个构造函数都有一个prototype
属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
function Cat(name){
//构造函数自身的属性name
this.name = name;
}
Cat.sex = '女';
Cat.prototype.age = '12';
var cat = new Cat('大黄');
cat.age;//12
cat.sex;//undefine 也就是说明实例只能继承构造函数原型上的属性和方法
cat.hasOwnProperty("name");//true hasOwnProperty判断是自己本身的属性还是继承的
cat.hasOwnProperty("age");//false
JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__
的内置属性,用于指向创建它的函数对象的原型对象prototype
。
cat.__proto__===Cat.prototype;//true
同样,Cat.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype
Cat.prototype.__proto__=== Object.prototype;//true
继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null
Object.prototype.__proto__;//null
我们把这个有__proto__
串起来的直到Object.prototype.__proto__
为null
的链叫做原型链。