1.成员速写
如果对象字面量初始化时,成员的名称来自于一个变量,并且和变量的名称相同,可以简写。
function createUser(loginId, loginPwd, nickName) {const sayHello = function () {console.log("loginId", this.loginId, "nickname", this.nickName)}return {loginId:loginId,loginPwd:loginPwd,nickName:nickName,sayHello,id: Math.random()}}const u = createUser("abc", "123", "aaa");u.sayHello();
function createUser(loginId, loginPwd, nickName) {const sayHello = function () {console.log("loginId", this.loginId, "nickname", this.nickName)}return {loginId,loginPwd,nickName,sayHello,id: Math.random()}}const u = createUser("abc", "123", "aaa");u.sayHello();
2.方法速写
对象字面量初始化时,方法可以省略冒号和function关键字
const user = {name: "程晓白",age: 16,sayHello:function(){console.log(this.name, this.age)}}user.sayHello();
const user = {name: "程晓白",age: 16,sayHello(){console.log(this.name, this.age)}}user.sayHello();
3.计算属性
初始化对象时,某些属性名可能来自于某个表达式的值,在ES6中,可以使用中括号来表示该属性名是通过计算得到的。
const prop1 = "name2";const prop2 = "age2";const prop3 = "sayHello2";const user = {[prop1]: "程晓白",[prop2]: 16,[prop3](){console.log(this[prop1], this[prop2])}}user[prop3]();console.log(user)
4.Object中新增的API
/*** 用于判断两个函数是否相等,跟===的判断是一致的,除了以下两点* 1.NaN和NaN相等* 2.+0和-0不相等*/console.log(Object.is(NaN, NaN));console.log(Object.is(+0, -0));
/*** 用于混合对象*/const obj1 = {a:1,b:2,c:3,}const obj2 = {a:4,d:5,e:6,}const obj = Object.assign({},obj1,obj2);console.log(obj);
/*** getOwnPropertyNames排序问题:* 在之前,官方没有给出具体的排序规则,如何排序是根据浏览器来排序的,ES6中,这个排序问题得到统一,规则如下:* 1.先排数字(升序)* 2.再排其他(书写顺序)*/const obj = {a:1,b:2,c:3,0:0,}console.log(Object.getOwnPropertyNames(obj));
/*** setPrototypeOf:* 用于设置某个对象的隐式原型** 例如:setPrototypeOf(obj1,obj2),相当于obj1.__proto__ = obj2*/const obj1 = {a:1,}const obj2 = {b:1,}console.log(Object.setPrototypeOf(obj1,obj2));
5.面向对象
面向对象:一种编程思想,跟具体的语言
对比面向过程:
- 面向过程:思考的切入点是功能的步骤
- 面向对象:思考的切入点是对象的划分
6.构造函数
ES6之前构造函数存在的问题: 属性和原型方法定义分离,降低了可读性 原型成员可以被枚举 默认情况下,构造函数仍然可以被当做普通函数使用
类的定义:面向对象中,对象的所有成员叫做类 类的特点: 类声明不会被提升,与let和const一样,存在暂时性死区 类中的所有代码均在严格模式下执行 类的所有方法都是不可枚举的 类的所有方法都无法被当作构造函数使用 类的构造器必须使用new来调用
//构造函数 构造器function Animal(type, name, age, sex) {this.type = type;this.name = name;this.age = age;this.sex = sex;}//定义实例方法(原型方法)Animal.prototype.print = function () {console.log(`【种类】:${this.type}`);console.log(`【名字】:${this.name}`);console.log(`【年龄】:${this.age}`);console.log(`【性别】:${this.sex}`);}const a = new Animal("狗", "旺财", 3, "男");a.print();for (const prop in a) {console.log(prop)}
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}`);}}const a = new Animal("狗", "旺财", 3, "男");a.print();for (const prop in a) {console.log(prop)}
7.类的书写方式
1.可计算的成员名 2.getter和setter Object.defineProperty 可定义某个对象成员属性的读取和设置 使用getter和setter控制的属性,不在原型上 3.静态成员 构造函数本身的成员 使用static关键字定义的成员即静态成员 4.字段初始化器(ES7) 注意: 1). 使用static的字段初始化器,添加的是静态成员 2). 没有使用static的字段初始化器,添加的成员位于对象上 3). 箭头函数在字段初始化器位置上,指向当前对象 5.类表达式 6.[扩展]装饰器(ES7)(Decorator) 横切关注点 装饰器的本质是一个函数
const printName = "print";class Animal {constructor(type, name, age, sex) {this.type = type;this.name = name;this.age = age;this.sex = sex;}[printName]() {console.log(`【种类】:${this.type}`);console.log(`【名字】:${this.name}`);console.log(`【年龄】:${this.age}`);console.log(`【性别】:${this.sex}`);}}const a = new Animal("狗", "旺财", 3, "男");a[printName]();
const printName = "print";class Animal {constructor(type, name, age, sex) {this.type = type;this.name = name;this.age = age;this.sex = sex;}//创建一个age属性,并给它加上getter,读取该属性时,会运行该函数get age() {return this._age + "岁";}//创建一个age属性,并给它加上setter,给该属性赋值时,会运行该函数set age(age) {if (typeof age !== "number") {throw new TypeError("age property must be a number");}if (age < 0) {age = 0;}else if (age > 1000) {age = 1000;}this._age = age;}[printName]() {console.log(`【种类】:${this.type}`);console.log(`【名字】:${this.name}`);console.log(`【年龄】:${this.age}`);console.log(`【性别】:${this.sex}`);}}var a = new Animal("狗", "旺财", 3, "男");
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}`);}}var a = new Animal("狗", "旺财", 3, "男");
class Chess {constructor(name) {this.name = name;}static width = 50;static height = 50;static method() {}}console.log(Chess.width)console.log(Chess.height)Chess.method();
class Test {static a = 1;b = 2;c = 3;constructor() {this.d = this.b + this.c;}}const t = new Test();console.log(t)
class Test {@Obsoleteprint() {console.log("print方法")}}function Obsolete(target, methodName, descriptor) {// function Test// { value: function print(){}, ... }// console.log(target, methodName, descriptor);const oldFunc = descriptor.valuedescriptor.value = function (...args) {console.warn(`${methodName}方法已过时`);oldFunc.apply(this, args);}}
8.类的继承
如果两个类A和B,如果可以描述为:B 是 A,则,A和B形成继承关系 如果B是A,则:
- B继承自A
- A派生B
- B是A的子类
- A是B的父类 如果A是B的父类,则B会自动拥有A中的所有实例成员。 新的关键字: extends:继承,用于类的定义 super
ES6中如果定义了constructor,并且该类是子类,则必须在constructor的第一行手动调用父类的构造函数 如果子类不写constructor,则会有默认的构造器,该构造器需要的参数和父类一致,并且自动调用父类构造器 用JS制作抽象类 抽象类:一般是父类,不能通过该类创建对象 正常情况下,this的指向,this始终指向具体的类的对象
直接当作函数调用,表示父类构造函数如果当作对象使用,则表示父类的原型
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}`);}jiao() {throw new Error("动物怎么叫的?");}}class Dog extends Animal {constructor(name, age, sex) {super("犬类", name, age, sex);// 子类特有的属性this.loves = "吃骨头";}print() {//调用父类的printsuper.print();//自己特有的代码console.log(`【爱好】:${this.loves}`);}//同名方法,会覆盖父类jiao() {console.log("旺旺!");}}//下面的代码逻辑有误const a = new Dog("旺财", 3, "公")a.print();
