1.成员速写

如果对象字面量初始化时,成员的名称来自于一个变量,并且和变量的名称相同,可以简写。

  1. function createUser(loginId, loginPwd, nickName) {
  2. const sayHello = function () {
  3. console.log("loginId", this.loginId, "nickname", this.nickName)
  4. }
  5. return {
  6. loginId:loginId,
  7. loginPwd:loginPwd,
  8. nickName:nickName,
  9. sayHello,
  10. id: Math.random()
  11. }
  12. }
  13. const u = createUser("abc", "123", "aaa");
  14. u.sayHello();
  1. function createUser(loginId, loginPwd, nickName) {
  2. const sayHello = function () {
  3. console.log("loginId", this.loginId, "nickname", this.nickName)
  4. }
  5. return {
  6. loginId,
  7. loginPwd,
  8. nickName,
  9. sayHello,
  10. id: Math.random()
  11. }
  12. }
  13. const u = createUser("abc", "123", "aaa");
  14. u.sayHello();

2.方法速写

对象字面量初始化时,方法可以省略冒号和function关键字

  1. const user = {
  2. name: "程晓白",
  3. age: 16,
  4. sayHello:function(){
  5. console.log(this.name, this.age)
  6. }
  7. }
  8. user.sayHello();
  1. const user = {
  2. name: "程晓白",
  3. age: 16,
  4. sayHello(){
  5. console.log(this.name, this.age)
  6. }
  7. }
  8. user.sayHello();

3.计算属性

初始化对象时,某些属性名可能来自于某个表达式的值,在ES6中,可以使用中括号来表示该属性名是通过计算得到的。

  1. const prop1 = "name2";
  2. const prop2 = "age2";
  3. const prop3 = "sayHello2";
  4. const user = {
  5. [prop1]: "程晓白",
  6. [prop2]: 16,
  7. [prop3](){
  8. console.log(this[prop1], this[prop2])
  9. }
  10. }
  11. user[prop3]();
  12. console.log(user)

4.Object中新增的API

  1. /**
  2. * 用于判断两个函数是否相等,跟===的判断是一致的,除了以下两点
  3. * 1.NaN和NaN相等
  4. * 2.+0和-0不相等
  5. */
  6. console.log(Object.is(NaN, NaN));
  7. console.log(Object.is(+0, -0));
  1. /**
  2. * 用于混合对象
  3. */
  4. const obj1 = {
  5. a:1,
  6. b:2,
  7. c:3,
  8. }
  9. const obj2 = {
  10. a:4,
  11. d:5,
  12. e:6,
  13. }
  14. const obj = Object.assign({},obj1,obj2);
  15. console.log(obj);
  1. /**
  2. * getOwnPropertyNames排序问题:
  3. * 在之前,官方没有给出具体的排序规则,如何排序是根据浏览器来排序的,ES6中,这个排序问题得到统一,规则如下:
  4. * 1.先排数字(升序)
  5. * 2.再排其他(书写顺序)
  6. */
  7. const obj = {
  8. a:1,
  9. b:2,
  10. c:3,
  11. 0:0,
  12. }
  13. console.log(Object.getOwnPropertyNames(obj));
  1. /**
  2. * setPrototypeOf:
  3. * 用于设置某个对象的隐式原型
  4. *
  5. * 例如:setPrototypeOf(obj1,obj2),相当于obj1.__proto__ = obj2
  6. */
  7. const obj1 = {
  8. a:1,
  9. }
  10. const obj2 = {
  11. b:1,
  12. }
  13. console.log(Object.setPrototypeOf(obj1,obj2));

5.面向对象

面向对象:一种编程思想,跟具体的语言
对比面向过程:

  • 面向过程:思考的切入点是功能的步骤
  • 面向对象:思考的切入点是对象的划分

    6.构造函数

    ES6之前构造函数存在的问题: 属性和原型方法定义分离,降低了可读性 原型成员可以被枚举 默认情况下,构造函数仍然可以被当做普通函数使用

类的定义:面向对象中,对象的所有成员叫做类 类的特点: 类声明不会被提升,与let和const一样,存在暂时性死区 类中的所有代码均在严格模式下执行 类的所有方法都是不可枚举的 类的所有方法都无法被当作构造函数使用 类的构造器必须使用new来调用

  1. //构造函数 构造器
  2. function Animal(type, name, age, sex) {
  3. this.type = type;
  4. this.name = name;
  5. this.age = age;
  6. this.sex = sex;
  7. }
  8. //定义实例方法(原型方法)
  9. Animal.prototype.print = function () {
  10. console.log(`【种类】:${this.type}`);
  11. console.log(`【名字】:${this.name}`);
  12. console.log(`【年龄】:${this.age}`);
  13. console.log(`【性别】:${this.sex}`);
  14. }
  15. const a = new Animal("狗", "旺财", 3, "男");
  16. a.print();
  17. for (const prop in a) {
  18. console.log(prop)
  19. }
  1. class Animal {
  2. constructor(type, name, age, sex) {
  3. this.type = type;
  4. this.name = name;
  5. this.age = age;
  6. this.sex = sex;
  7. }
  8. print() {
  9. console.log(`【种类】:${this.type}`);
  10. console.log(`【名字】:${this.name}`);
  11. console.log(`【年龄】:${this.age}`);
  12. console.log(`【性别】:${this.sex}`);
  13. }
  14. }
  15. const a = new Animal("狗", "旺财", 3, "男");
  16. a.print();
  17. for (const prop in a) {
  18. console.log(prop)
  19. }

7.类的书写方式

1.可计算的成员名 2.getter和setter Object.defineProperty 可定义某个对象成员属性的读取和设置 使用getter和setter控制的属性,不在原型上 3.静态成员 构造函数本身的成员 使用static关键字定义的成员即静态成员 4.字段初始化器(ES7) 注意: 1). 使用static的字段初始化器,添加的是静态成员 2). 没有使用static的字段初始化器,添加的成员位于对象上 3). 箭头函数在字段初始化器位置上,指向当前对象 5.类表达式 6.[扩展]装饰器(ES7)(Decorator) 横切关注点 装饰器的本质是一个函数

  1. const printName = "print";
  2. class Animal {
  3. constructor(type, name, age, sex) {
  4. this.type = type;
  5. this.name = name;
  6. this.age = age;
  7. this.sex = sex;
  8. }
  9. [printName]() {
  10. console.log(`【种类】:${this.type}`);
  11. console.log(`【名字】:${this.name}`);
  12. console.log(`【年龄】:${this.age}`);
  13. console.log(`【性别】:${this.sex}`);
  14. }
  15. }
  16. const a = new Animal("狗", "旺财", 3, "男");
  17. a[printName]();
  1. const printName = "print";
  2. class Animal {
  3. constructor(type, name, age, sex) {
  4. this.type = type;
  5. this.name = name;
  6. this.age = age;
  7. this.sex = sex;
  8. }
  9. //创建一个age属性,并给它加上getter,读取该属性时,会运行该函数
  10. get age() {
  11. return this._age + "岁";
  12. }
  13. //创建一个age属性,并给它加上setter,给该属性赋值时,会运行该函数
  14. set age(age) {
  15. if (typeof age !== "number") {
  16. throw new TypeError("age property must be a number");
  17. }
  18. if (age < 0) {
  19. age = 0;
  20. }
  21. else if (age > 1000) {
  22. age = 1000;
  23. }
  24. this._age = age;
  25. }
  26. [printName]() {
  27. console.log(`【种类】:${this.type}`);
  28. console.log(`【名字】:${this.name}`);
  29. console.log(`【年龄】:${this.age}`);
  30. console.log(`【性别】:${this.sex}`);
  31. }
  32. }
  33. var a = new Animal("狗", "旺财", 3, "男");
  1. class Animal {
  2. constructor(type, name, age, sex) {
  3. this.type = type;
  4. this.name = name;
  5. this.age = age;
  6. this.sex = sex;
  7. }
  8. print() {
  9. console.log(`【种类】:${this.type}`);
  10. console.log(`【名字】:${this.name}`);
  11. console.log(`【年龄】:${this.age}`);
  12. console.log(`【性别】:${this.sex}`);
  13. }
  14. }
  15. var a = new Animal("狗", "旺财", 3, "男");
  1. class Chess {
  2. constructor(name) {
  3. this.name = name;
  4. }
  5. static width = 50;
  6. static height = 50;
  7. static method() {
  8. }
  9. }
  10. console.log(Chess.width)
  11. console.log(Chess.height)
  12. Chess.method();
  1. class Test {
  2. static a = 1;
  3. b = 2;
  4. c = 3;
  5. constructor() {
  6. this.d = this.b + this.c;
  7. }
  8. }
  9. const t = new Test();
  10. console.log(t)
  1. class Test {
  2. @Obsolete
  3. print() {
  4. console.log("print方法")
  5. }
  6. }
  7. function Obsolete(target, methodName, descriptor) {
  8. // function Test
  9. // print
  10. // { value: function print(){}, ... }
  11. // console.log(target, methodName, descriptor);
  12. const oldFunc = descriptor.value
  13. descriptor.value = function (...args) {
  14. console.warn(`${methodName}方法已过时`);
  15. oldFunc.apply(this, args);
  16. }
  17. }

8.类的继承

如果两个类A和B,如果可以描述为:B 是 A,则,A和B形成继承关系 如果B是A,则:

  1. B继承自A
  2. A派生B
  3. B是A的子类
  4. A是B的父类 如果A是B的父类,则B会自动拥有A中的所有实例成员。 新的关键字: extends:继承,用于类的定义 super
    1. 直接当作函数调用,表示父类构造函数
    2. 如果当作对象使用,则表示父类的原型
    ES6中如果定义了constructor,并且该类是子类,则必须在constructor的第一行手动调用父类的构造函数 如果子类不写constructor,则会有默认的构造器,该构造器需要的参数和父类一致,并且自动调用父类构造器 用JS制作抽象类 抽象类:一般是父类,不能通过该类创建对象 正常情况下,this的指向,this始终指向具体的类的对象
  1. class Animal {
  2. constructor(type, name, age, sex) {
  3. if (new.target === Animal) {
  4. throw new TypeError("你不能直接创建Animal的对象,应该通过子类创建")
  5. }
  6. this.type = type;
  7. this.name = name;
  8. this.age = age;
  9. this.sex = sex;
  10. }
  11. print() {
  12. console.log(`【种类】:${this.type}`);
  13. console.log(`【名字】:${this.name}`);
  14. console.log(`【年龄】:${this.age}`);
  15. console.log(`【性别】:${this.sex}`);
  16. }
  17. jiao() {
  18. throw new Error("动物怎么叫的?");
  19. }
  20. }
  21. class Dog extends Animal {
  22. constructor(name, age, sex) {
  23. super("犬类", name, age, sex);
  24. // 子类特有的属性
  25. this.loves = "吃骨头";
  26. }
  27. print() {
  28. //调用父类的print
  29. super.print();
  30. //自己特有的代码
  31. console.log(`【爱好】:${this.loves}`);
  32. }
  33. //同名方法,会覆盖父类
  34. jiao() {
  35. console.log("旺旺!");
  36. }
  37. }
  38. //下面的代码逻辑有误
  39. const a = new Dog("旺财", 3, "公")
  40. a.print();