属性的简洁表示法
- ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 上面代码中,变量foo直接写在大括号里面。这时,属性名就是变量名, 属性值
//就是变量值
- 除了属性简写,方法也可以简写。
// 在定义一个对象里面应用里面应用
const obj = {
method() {
return "Hello!";
}
};
// 等同于
const obj = {
method: function() {
return "Hello!";
}
};
--------------------------------------------------------------------
// 在定义一个类里面应用
class Ser{
clear(){
console.log("测试1")
}
clear = function() {
console.log('测试1')
}
}
let Serious = new Ser()
Serious.clear()
注意,简写的对象方法不能用作构造函数,会报错。
const obj = {
f() {
this.foo = 'bar';
}
};
let obj2 = new obj.f() // 报错
属性名表达式
- ES6 允许字面量定义对象时,用表达式作为对象的属性名。
let lastWord = 'last word';
const a = {
'first word': 'hello', // ES5 的写法
[lastWord]: 'world' // Es6 的写法
};
a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
const keyA = {a: 1};
const keyB = {b: 2};
const myObject = {
[keyA]: 'valueA',
[keyB]: 'valueB'
};
myObject // Object {[object Object]: "valueB"}
// 上面代码中,[keyA]和[keyB]得到的都是[object Object],
// 所以[keyB]会把[keyA]覆盖掉,而myObject最后只有一个[object Object]属性
方法的 name 属性
const person = {
sayName() {
console.log('hello!');
},
};
person.sayName.name // "sayName"
// 方法的name属性返回函数名(即方法名)
- 有两种特殊情况:
bind
方法创造的函数,name
属性返回bound
加上原函数
的名字;Function构造函数
创造的函数,name
属性返回anonymous
。
// 构造函数
(new Function()).name // "anonymous"
// bind()方法创建函数
var doSomething = function() {
// ...
};
doSomething.bind().name // "bound doSomething"
// bind()函数的作用是将函数的 this 锁定,不会因不同的调用而改变 this的值
属性的可枚举性和遍历
ES6 一共有 5 种方法可以遍历对象的属性。
(1)for…in
for...in
循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
(2)Object.keys(obj)
Object.keys
返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。(比较常用)
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames
返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols
返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys
返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
let newPerson = {
name:'Jack',
age: 18,
school:'Gdufs',
grade:'University',
index(){
console.log('this is a great person!')
}
}
// 遍历对象
console.log(Object.keys(newPerson)) //["name", "age", "school", "grade", "index"]
super 关键字
- super关键字用于访问和调用一个对象的父对象上的函数。
- ·
注意,super关键字表示原型对象时,只能用在对象的方法之中,用在其他地方都会报错。
- 原型对象:函数的内置属性
prototype(指针)
指向原型对象,实例对象通过_ptoto_
指向原型对象。 - 假设
var s = new student()
=>s.__ptoto__ = student.prototype
这个关系式成立
let o1 = { a: 1 };
let o2 = { b: 2 };
o2.__proto__ = o1;
// o2 的原型对象是 o1
在对象字面量中使用super.prop
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find() {
return super.foo;
}
};
Object.setPrototypeOf(obj, proto); // 为 obj 设置原型对象 proto
// 所以 super.foo 可以引用到 proto 里面的方法
obj.find() // "hello"
扩展运算符
- 解构赋值的经典例子
const o = Object.create({ x: 1, y: 2 });
o.z = 3;
let { x, ...newObj } = o;
let { y, z } = newObj;
x // 1
y // undefined
z // 3
// 出现这种情况的原因:扩展运算符(...)只能够继承 赋值对象的属性而不能够
// 继承原型对象的属性,Object.create({x:1, y:2})是为 o 对象指定原型对象,
// 而 o 本身的属性就只有 z,所以会出现这样的结果。
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
// 对象嵌套对象数组的解构
let objc = {name:'Ming',age:18}
console.log({...objc}) // {name: "Ming", age: 18}
console.log({...['a', 'b', 'c']}) // {0: "a", 1: "b", 2: "c"}
//扩展运算符可以用于合并两个对象。
let ab = { ...a, ...b };
// 等同于
let ab = Object.assign({}, a, b);
- 如果用户自定义的属性,放在扩展运算符后面,则扩展运算符内部的
同名属性
会被覆盖掉。
let a = {x:2, y:3}
let aWithOverrides = { ...a, x: 1, y: 2 };
console.log(aWithOverrides) //{x: 1, y: 2} 覆盖掉原来的属性
- 与数组的扩展运算符一样,对象的扩展运算符后面可以跟
表达式
。
let x = 2
const obj = {
...(x > 1 ? {a: 1} : {}),
b: 2,
};
obj // => {a:1, b:2}
链判断运算符
let jsc = {name:'Nacy', age:18}
let able = jsc?.name // Nacy 在判断jsc != null /undefined 后执行 jsc.name
?.运算符
,直接在链式调用的时候判断,左侧的对象是否为null或undefined
。如果是的,就不再往下运算,而是返回undefined
。
const firstName = message?.body?.user?.firstName || 'default';
// 他会沿 从左向右的方向进行判断
链判断运算符有三种用法。
obj?.prop
// 对象属性obj?.[expr]
// 同上func?.(...args)
// 函数或对象方法的调用
下面是这个运算符常见的使用形式,以及不使用该运算符时的等价形式。
a?.b
// 等同于
a == null ? undefined : a.b
a == null || undefined ? undefined : a.b
// 这两种写法没有区别,因为在 javascript里面, null == undefined => true
// 但是注意 undefined === null => false
a?.[x]
// 等同于
a == null? undefined : a[x]
a?.b()
// 等同于
a == null ? undefined : a.b()
a?.()
// 等同于
a == null ? undefined : a()
- 如果属性链有圆括号,链判断运算符对圆括号外部没有影响,只对圆括号内部有影响。
(a?.b).c
// 等价于
(a == null ? undefined : a.b).c
// 上面代码中,?.对圆括号外部没有影响,不管a对象是否存在,圆括号后面的.c总
//是会执行。
- 右侧不得为十进制数值
=> 如果?.
后面紧跟一个十进制数字,那么?.不再被看成是一个完整的运算符,而会按照三元运算符
进行处理,也就是说,那个小数点会归属于后面的十进制数字
,形成一个小数。
null判断运算符
ES2020 引入了一个新的 Null 判断运算符??。它的行为类似 ||
,但是只有运算符左侧的值为null或undefined
时,才会返回右侧的值。
??
有一个运算优先级问题,如果与 && 或者 || 混合使用的话要添加括号来标识谁先谁后。
(lhs && middle) ?? rhs;
lhs && (middle ?? rhs);
// 先执行括号内的再执行括号外的