新增对象字面量语法
1. 成员速写
如果对象字面量初始化时,成员的名称来自于一个变量,并且和变量的名称相同,则可以进行简写。
function person(userName, password, nickName) {
return {
userName: userName, // 原本
password, // 简写
nickName
}
}
2. 方法速写
对象字面初始化时,方法可以省略冒号和function关键字
const obj = {
name : "abc",
age : 20,
//简写前
sayHello: function() {
console.log(this.name)
}
//简写后
sayHello(){
console.log(this.name)
}
}
3. 计算属性名
有的时候初始化对象,某些属性名可能来自于某个表达式的值,在ES6,可以使用中括号来表示该属性名是通过计算得到的。
let name = "name", age = "age";
const obj = {
[name]: "abc",
[age]: 20
}
// 调用
console.log(obj[name])
Object的新增API
1. Object.is
用于判断两个数据是否相等,基本上跟严格相等(===)是一致的,除了以下两点:
- NaN和NaN相等
- +0和-0不相等
console.log(NaN === NaN); // false
console.log(+0 === -0) // true
console.log(Object.is(NaN, NaN)) // true
console.log(Object.is(+0, -0)) // false
2. Object.assign
用于混合对象
const obj1 = {
a: "1",
b: "2",
c: "3"
}
const obj2 = {
a: "a",
b: "b",
d: "d"
}
const obj3 = {
...obj1,
...obj2
}
const obj4 = Object.assign({}, obj1, obj2)
3. Object.getOwnPropertyNames 的枚举顺序
这个方法之前就存在,只不过官方没有明确要求对属性顺序如何排序,如何排序完全由浏览器厂商自行决定。
ES6规定了该方法返回的数组排序如下:
- 先排数字,按照升序排序
- 再排其他,按照书写顺序排序
const obj = {
d: "1",
b: "2",
c: "3",
0: "A",
10: "B",
5: "C"
}
console.log(Object.getOwnPropertyNames(obj)) // ["0", "5", "10", "d", "b", "c"]
4. Object.setPrototypeOf
该方法用于设置某个对象的隐式原型
比如:Object.setPrototypeOf(obj1, obj2)
== obj1.__proto__ = obj2
const obj1 = {
a: "1"
}
const obj2 = {
b: "2"
}
const obj3 = Object.setPrototypeOf(obj1, obj2)
console.log(obj1 === obj3) // true
面向对象简介
面向对象:一种编程思想,跟具体的语言
对比面向过程:
- 面向过程:思考的切入点是功能的步骤
// 大象关进冰箱
// 打开门
function openFridge (params) {
}
openFridge()
// 把大象装进去
function putIn() {
}
putIn()
// 把门关上
function closeFridge() {
}
closeFridge()
- 面向对象:思考的切入点是对象的划分
// 一个冰箱原型
function Fridge() {
}
// 一个大象原型
function Elephant () {
// 大小,体重,等等
}
// 给冰箱原型增加三个方法
Fridge.prototype.openFridge = function() {
// 打开冰箱
}
Fridge.prototype.closeFridge = function () {
// 把冰箱关上
}
Fridge.prototype.putIn = function(ele) {
// 把什么东西放进去
// -----
// this.openFridge() // 打开冰箱
// this.closeFridge() // 把冰箱门关上
}
// 调用冰箱原型上的方法
//打开冰箱
let fridge = new Fridge();
fridge.openFridge();
//把大象装进去
let elephant = new Elephant();
fridge.putIn(elephant)
//把冰箱门关上
fridge.closeFridge()
//putIn方法里面的参数可以随意组合,往冰箱里放什么东西都可以,这体现了面向对象写法的好处
面向对象的写法更适合多人开发的大型项目,模块化开发,
类:构造函数的语法糖
传统构造函数的问题
- 属性和原型方法定义分离,降低了可读性
- 原型成员可以被枚举
- 默认情况下,构造函数仍然可以被当作普通函数使用
// 传统写法
function Animal (type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
// 给构造函数Animal增加打印方法
Animal.prototype.print = function () {
console.log(`【种类】:${this.type}`)
console.log(`【名字】:${this.name}`)
console.log(`【年龄】:${this.age}`)
console.log(`【性别】:${this.sex}`)
}
let dog = new Animal("狗", "柴", "3岁", "公")
dog.print() // 调用原型上的方法
类的特点
- 类声明不会被提升,与
let
和const
一样,存在暂时性死区 - 类中的所有代码均在严格模式下执行
- 类的所有方法都是不可枚举的
- 类的所有方法内部都无法被当作构造函数使用
- 类的构造器必须使用
new
使用
// ES6类的写法
class Animal {
constructor(type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
print() {
console.log(`【种类】:${this.type}`)
console.log(`【名字】:${this.name}`)
console.log(`【年龄】:${this.age}`)
console.log(`【性别】:${this.sex}`)
}
}
let dog = new Animal("狗", "柴", "3岁", "公")
dog.print()
类的其他书写方式
1. 可计算的成员名
const newProp = "newProp"
class Animal {
constructor(type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
[newProp]() { // 声明
console.log(`【种类】:${this.type}`)
console.log(`【名字】:${this.name}`)
console.log(`【年龄】:${this.age}`)
console.log(`【性别】:${this.sex}`)
}
}
let dog = new Animal("狗", "柴", "3岁", "公")
dog[newProp]() // 调用
2. getter和setter
使用getter
和setter
定义的属性不在原型上
const newProp = "newProp"
class Animal {
constructor(type, name, age, sex) {
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
get age() { // 获取属性 get
return this._age
}
set age(age) { // 设置属性 set
if(age < 0) {
age = "0"
} else if(age > 1000) {
age = "1000"
}
this._age = age
}
[newProp]() {
console.log(`【种类】:${this.type}`)
console.log(`【名字】:${this.name}`)
console.log(`【年龄】:${this.age}`)
console.log(`【性别】:${this.sex}`)
}
}
let dog = new Animal("狗", "柴", "10岁", "公")
dog[newProp]()
3. 静态成员
构造函数本身的成员
使用static
关键字定义成员,即静态成员
class box {
constructor (name) {
this.name = name;
}
static width = 100;
static height = 100;
static fn() {
console.log("这是方法")
}
}
console.log(box.width) // 100
console.log(box.height) // 100
box.fn() // 调用静态方法
4. 字段初始化器 [ES7]
注意:
1)使用static
的字段初始化器,添加的是静态成员
2)没有使用static
的字段初始化器,添加的成员位于对象上
3)箭头函数在字段初始化器位置上,指向当前对象
class Test {
static a = 1
b = 2
c = 3
constructor (){
// b = 2, c = 3 相当于
// this.b = 2
// this.c = 3
this.d = this.c + this.b // 5
}
}
const t = new Test()
console.log(t) //Test {b: 2, c: 3}
5. 类表达式
用法和之前的相同
// 匿名类,类表达式
const A = class {
b = 2
c = 3
}
const a = new A()
console.log(a)
6. 装饰器 [ES7]
类的继承
新的关键字:
-
extends
:继承,用于类的定义 -
super
-
直接当做函数调用,表示父类构造函数
ES6要求,如果定义
constructor
,并且该类是子类,则必须在constructor
的第一行手动调用父类的构造函数如果子类不写
constructor
,则会有默认的构造器,该构造器需要的参数和父类一致,并且自动调用父类构造器 如果当作对象使用,则表示父类的原型
-
【冷知识】
- 用JS制作抽象类
- 抽象类:一般是父类,不能通过该类创建对象
- 正常情况下
this
的指向始终指向具体的类的对象
// ES6类的写法
// 父类
class Animal {
constructor(type, name, age, sex) {
if (new.target === Animal) {
throw new TypeError("不能直接创建Animal对象,应该通过子类创建")
}
this.type = type;
this.name = name;
this.age = age;
this.sex = sex;
}
print () {
console.log(`【种类】:${this.type}`)
console.log(`【名字】:${this.name}`)
console.log(`【年龄】:${this.age}`)
console.log(`【性别】:${this.sex}`)
}
}
// 子类
class Dog extends Animal {
constructor(name, age, sex) {
super("犬类", name, age, sex)
this.hobby = "吃骨头" // 子类特有属性
}
print () {
super.print() // 调用父类上的方法
console.log(`【爱好】:${this.hobby}`) // 给父类增加一个子类特有方法
}
}
// let dog = new Animal("柴", "3岁", "公") // 抛出错误,throw new TypeError("不能直接创建Animal对象,应该通过子类创建")
let dog = new Dog("柴", "3岁", "公")
dog.print() // 如果子类有这个方法就执行子类的方法,如果子类没有就执行父类的方法。