博客列表 >类成员与类继承

类成员与类继承

王佳祥
王佳祥原创
2020年09月07日 10:16:00760浏览

类成员与类继承

一、类表达式

  1. //类表达式
  2. let PersonClass = class {
  3. //构造方法
  4. constructor(name) {
  5. this.name = name;
  6. }
  7. sayName() {
  8. return this.name;
  9. }
  10. };
  11. let person = new PersonClass("小丽");
  12. console.log(person.sayName());
  13. //类作为参数使用
  14. let createObj = function (className, ...args) {
  15. return new className(...args);
  16. };
  17. let obj = createObj(
  18. class {
  19. hello() {
  20. return "hello JS";
  21. }
  22. }
  23. );
  24. console.log(obj.hello());
  25. //立即实例化一个类表达式,创建一个单例
  26. //(函数/类声明)(调用参数列表) 类的前面加new
  27. let user = new (class {
  28. constructor(email) {
  29. this.email = email;
  30. }
  31. getEmail() {
  32. return this.email;
  33. }
  34. })("孙悟空");
  35. console.log(user.getEmail());


二、类的构造方法

  1. class User {
  2. constructor() {
  3. console.log(this);
  4. return Object.create(null);
  5. }
  6. }
  7. const user = new User();
  8. console.log(user);


三、类的实例属性和原型属性

  1. class User {
  2. constructor(id, name) {
  3. //实例属性:直接绑定到实例(this)上面的属性
  4. this.id = id;
  5. this.name = name;
  6. //实例方法
  7. this.getName = () => console.log("hello", this.name);
  8. }
  9. //原型方法
  10. show() {
  11. console.log(this.id, this.name);
  12. }
  13. }
  14. const user = new User(1, "admin");
  15. console.log(user);
  16. console.log(user.show());
  17. console.log(user.show());


四、存取属性

  1. function User1(age) {
  2. this.age = age;
  3. }
  4. //公共方法或属性定义在函数的原型对象上
  5. User1.prototype.email = "admin@qq.com";
  6. console.dir(User1);
  7. const user1 = new User1();
  8. console.log(user1.email);
  9. //在User.prototype原型对象上设置"存取器属性"
  10. Object.defineProperty(User1.prototype, "verfiyAge", {
  11. get: () => this.age,
  12. set: (value) => {
  13. if (value >= 18 && value <= 60) this.age = value;
  14. },
  15. //configurable控制属性是否可配置
  16. configurable: true,
  17. //writable控制属性是否可直接修改
  18. //enumerable控制属性是否可被枚举出来
  19. /*
  20. 1.writable只限制了能否直接赋值。
  21. 2.configurable为false依然能直接修改属性的值。
  22. 3.若writable和configurable都是false,则无法进行属性的修改。
  23. */
  24. enumerable: true,
  25. });
  26. let user = new User1(30);
  27. console.log(user);
  28. console.log(user.age);
  29. console.log(user.verfiyAge);
  30. user.verfiyAge = 40;
  31. console.log(user.age);
  32. //对象的原型永远等于它的构造函数的原型对象,对象上从它的构造函数的原型对象上继承成员(属性和方法)
  33. console.log(user.__proto__ === User1.prototype);
  34. console.log(user.constructor);
  35. console.log(user.__proto__ === user.constructor.prototype);


五、存取属性实现数据的双向绑定小案例

  1. <input type="text" />
  2. <p></p>
  3. <script>
  4. const obj = {};
  5. Object.defineProperty(obj, "hello", {
  6. set(value) {
  7. document.querySelector("input").value = value;
  8. document.querySelector("p").innerHTML = value;
  9. },
  10. });
  11. document.addEventListener("input", function (ev) {
  12. obj.hello = ev.target.value;
  13. });
  14. console.log(obj);


六、静态成员

  1. //静态成员的特征
  2. //1.不能被实例访问
  3. //2.不能被实例共享
  4. //3.必能通过类才可以访问
  5. //原生
  6. function User() {}
  7. //函数对象的静态成员就是函数的属性,直接添加
  8. User.site = "php中文网";
  9. User.say = () => `我是 "${User.site}" 的朱老师`;
  10. console.dir(User);
  11. console.log(User.hasOwnProperty("site"));
  12. console.log(User.hasOwnProperty("say"));
  13. console.log(User.hasOwnProperty("constructor"));
  14. console.log(User.hasOwnProperty("call"));
  15. console.log(User.hasOwnProperty("name"));
  16. //es6的类实现静态成员
  17. class UserClass {
  18. //原型方法
  19. hello() {
  20. return "欢迎大家来上我的课程";
  21. }
  22. //静态属性
  23. static position = "讲师";
  24. //静态方法
  25. static say() {
  26. return `我是一名:${UserClass.position}`;
  27. }
  28. }
  29. //访问原型方法
  30. console.log(new UserClass().hello());
  31. //访问静态成员
  32. console.log(UserClass.say());


七、类中的私有成员

  1. //1.原生实现私有成员
  2. function User() {
  3. //私有成员:是函数中的私有变量/局部变量来充当
  4. let course = "es6编程";
  5. let hello = () => `大家一定要好好学习${course}课程`;
  6. this.say = () => console.log(hello());
  7. }
  8. new User().say();
  9. //2.es6实现类中的私有成员
  10. class UserClass {
  11. //1.私有属性
  12. #salary;
  13. constructor(salary = 0) {
  14. this.#salary = salary;
  15. }
  16. //私有属性应该设置getter.setter
  17. //getter
  18. get salary() {
  19. return this.#salary;
  20. }
  21. //setter
  22. set salary(value) {
  23. if (value < this.salary) console.log("禁止降薪,否则辞职");
  24. else console.log((this.#salary = value));
  25. }
  26. //私有方法
  27. #max(arr) {
  28. return Math.max(...arr);
  29. }
  30. //私有方法只能在类中用
  31. getMax(arr) {
  32. return this.#max(arr);
  33. }
  34. //静态私有属性
  35. static #hobby = "摄影";
  36. static #eat() {
  37. return "我爱吃肉";
  38. }
  39. static getHobby() {
  40. return UserClass.#eat() + "和" + UserClass.#hobby;
  41. }
  42. // 原型方法中访问静态成员
  43. getHobby() {
  44. return UserClass.#eat() + "哈哈, 和 " + UserClass.#hobby;
  45. }
  46. }
  47. const user = new UserClass(5000);
  48. console.log(user);
  49. console.log(user.salary);
  50. user.salary = 2000;
  51. user.salary = 3000;
  52. console.log(UserClass.getHobby());
  53. console.log(new UserClass().getHobby());


八、类的继承:原生

  1. //原生是通过原型链来实现继承
  2. const obj = { name: "damin", age: 90 };
  3. //创建一个对象继承obj
  4. const newObj = Object.create(obj);
  5. console.log(newObj);
  6. console.log(newObj.__proto__.age === newObj.age);
  7. console.log(newObj.name, newObj.age);
  8. //1.父类
  9. function Vehicle(fuel, purpose) {
  10. this.fuel = fuel;
  11. this.purpose = purpose;
  12. }
  13. //公共/原型方法
  14. Vehicle.prototype.show = function () {
  15. return `燃料:${this.fuel}\n用途:${this.purpose}\n`;
  16. };
  17. console.dir(Vehicle);
  18. //2.子类
  19. function Car(fuel, purpose, color) {
  20. Vehicle.call(this, fuel, purpose);
  21. this.color = color;
  22. }
  23. //关键代码
  24. //更新当前子类的原型对象,这样才能实现真正意义上的继承
  25. Car.prototype = Object.create(Vehicle.prototype);
  26. //手工补上constructor
  27. Car.prototype = Car;
  28. //子类中重写父类的原型方法
  29. Car.prototype.show = function () {
  30. return Vehicle.prototype.show.call(this).concat(`颜色:${this.color}\n`);
  31. };
  32. //实例化子类
  33. const car = new Car("汽油", "家用", "白色");
  34. console.log(car.show());
  35. console.dir(Car);


九、es6中的类继承

  1. //父类
  2. class Vehicle {
  3. constructor(fuel, purpose) {
  4. this.fuel = fuel;
  5. this.purpose = purpose;
  6. }
  7. //原型方法
  8. show() {
  9. return `燃料:${this.fuel}\n用途:${this.purpose}\n`;
  10. }
  11. }
  12. //子类
  13. class Car extends Vehicle {
  14. constructor(fuel, purpose, color) {
  15. //调用父类的构造方法
  16. //super()必须是第一条,否则不能正确生成子类的this
  17. super(fuel, purpose);
  18. this.color = color;
  19. }
  20. //重写父类的原型方法
  21. show() {
  22. return super.show().concat(`颜色:${this.color}\n`);
  23. }
  24. }
  25. //super:
  26. //1.当成函数:super()代表父类的构造方法,必须用在子类的构造方法中的第一行
  27. //2.当成对象:super用在原型方法/静态方法,代码父类的原型对象
  28. //实例化子类
  29. const car = new Car("新能源", "出租车", "蓝色");
  30. console.log(car.show());


学习总结

1.类表达式

  • 类表达式是用来定义类的一种语法。和函数表达式相同的一点是,类表达式可以是命名也可以是匿名的。如果是命名类表达式,这个名字只能在类体内部才能访问到。JavaScript 的类也是基于原型继承的。

  • 语法

  1. const MyClass = class [className] [extends] {
  2. // class body
  3. };
  • 类可以作为参数使用

  • 可以立即实例化一个类表达式,(函数/类声明)(调用参数列表) 类的前面加new

2.类的构造函数

  • constructor 是一种用于创建和初始化class创建的对象的特殊方法。

  • 在一个类中只能有一个名为 “constructor” 的特殊方法。

  • 在一个构造方法中可以使用super关键字来调用一个父类的构造方法。

  • 如果没有显式指定构造方法,则会添加默认的 constructor 方法。

  • 如果不指定一个构造函数(constructor)方法, 则使用一个默认的构造函数(constructor)。

3.类的实例属性和原型属性

  • 实例属性:直接绑定到实例(this)上面的属性

  • 原型属性:绑定在原型(prototype)上的属性

4.存取属性

  • get语法将对象属性绑定到查询该属性时将被调用的函数。

  • get关键字可在对象内部使用,可为此对象创造一个伪属性

  • 在我们调用这个方法时,可以像访问对象的属性一样,不用加括号,就可以执行此方法,而这个方法会返回一个数,所以我们可以用get关键字为此对象创造一个伪属性。并且这个伪属性只可读,不可写。

  • 只需使用 delete,就可删除 getter

  • 使用Object.defineProperty()在现有对象上定义 getter

  • set关键字与get关键字的区别是,用set时,必须有且仅能有一个参数,而用get时,不能有参数。否则将会报错。并且,用set时,只能赋值,而不能取值

  • 通过get和set配合,对同一属性操作,就可以完成对实例对象赋值的权限的控制。由set,get关键字的特性可知,只有set,get同时用,才可以对同一属性进行存取。

5.静态成员

  • 静态成员的特征

    1. 1.不能被实例访问
    2. 2.不能被实例共享
    3. 3.必能通过类才可以访问
  • 函数对象的静态成员就是函数的属性,直接添加

  • 类(class)通过 static 关键字定义静态方法

  • 静态方法调用同一个类中的其他静态方法,可使用 this 关键字

  • 非静态方法中,不能直接使用 this 关键字来访问静态方法。而是要用类名来调用

6.类中的私有成员

原生
  • 私有成员:是函数中的私有变量/局部变量来充当
es6实现类中的私有成员
  • 私有实例字段使用 名称(发音为“哈希名称”)声明,这些名称以 #开头。 #是名称本身的一部分, 声明和访问时也需要加上

  • 从作用域之外引用名称是语法错误

  • 私有字段可以被类的构造方法(constructor)从内部声明

七、类的继承:原生

  • 原生是通过原型链来实现继承

  • 创建一个对象来继承

八、es6中的类继承

  • extends关键字用于类的继承

  • super()调用父类的构造方法

  • super()必须是第一条,否则不能正确生成子类的this

  • super的两种应用场景:

    1.当成函数:super()代表父类的构造方法,必须用在子类的构造方法中的第一行

    2.当成对象:super用在原型方法/静态方法,代码父类的原型对象

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议