javaScript-你不知道的类

Posted 火腿肠烧烤大赛冠军

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javaScript-你不知道的类相关的知识,希望对你有一定的参考价值。

类语法的定义

基础就是对原型的操作
声明和java差不多

  class User {
    constructor(name) {
      this.name = name;
    }
    getName() {
      return this.name;
    }
  }
  let hd = new User("123");
  console.log(hd.getName());

类的内部工作机制就是原型操作

类就是构造函数的语法糖
实质为操作prototype而已

对象属性的声明

constructor 内外都可以声明

  class User {
    site = "aaa";
    constructor(name) {
      this.name = name;
    }
    changeSite(value) {
      this.site = value;
    }
    show() {
      return `${this.site}:${this.name}`;
    }
  }
  let hd = new User("bbb");
  hd.changeSite("houdunren");
  console.log(hd.show());

class声明的方法为不能遍历

在继承时候 可遍历默认设置为false

在class中默认为严格模式

(部分指向windows的指针会失效)

静态属性使用

静态属性就是指构造函数自己的属性(不默认给它构造出来的对象使用)
在类中使用:大家一起可以用这个属性:

  class Request {
    static host = "https://www.baidu.com";
    api(url) {
      return Request.host + `/${url}`;
    }
  }
  let obj = new Request();
  console.log(obj.api("article"));

原理:
在当前构造函数的_proto_上加一个新的属性以便访问:

User.__proto__.name = function(){};

利用静态方法构造:

  class Member {
    constructor(name, age, sex) {
      this.name = name;
      this.age = age;
      this.sex = sex;
    }
    static create(...args) {
      return new this(...args);
    }
  }
  let xj = Member.create("SS", 19, "男");
  console.log(xj);

在类中使用访问器

设置就触发set、访问就触发get

  class Requset {
    constructor(host) {
      this.data = {};
      this.host = host;
    }
    set host(url) {
      if (!/^https?:\\/\\//i.test(url)) {
        throw new Error("地址错误");
      }
      this.data.host = url;
    }
    get host() {
      return this.data["host"];
    }
  }
  let ss = new Requset("https://sss.com");
  // hd.host = "https://sss.com";
  // hd.setUrl("https://sss.com");
  console.log(ss);

在这里插入图片描述

使用命名规则保护属性

  class User {
    //public
    _url = "https://sss.com";
    constructor(name) {
      this.name = name;
    }
    set url(url) {
      if (!/^https?:/i.test(url)) {
        throw new Error("非常网址");
      }
      this._url = url;
    }
  }
  let hd = new User("sss");
  hd.name = "李四";
  hd.url = "https://sss.com";
  console.log(hd);

使用Symbol定义protected属性

在这里插入图片描述

    const protecteds = Symbol();
    class Common {
      constructor() {
        this[protecteds] = {};
        this[protecteds].host = "https://sss.com";
      }
      set host(url) {
        if (!/^https?:/i.test(url)) {
          throw new Error("非常网址");
        }
        this[protecteds].host = url;
      }
      get host() {
        return this[protecteds].host;
      }
    }
    class User extends Common {
      constructor(name) {
        super();
        this[protecteds].name = name;
      }
      get name() {
        return this[protecteds].name;
      }
    }
    let hd = new User("sss");
    hd.host = "https://www.sss.com";
    // console.log(hd[Symbol()]);
    console.log(hd);
    console.log(hd.host);

使用WeakMap保护属性

  const protecteds = new WeakMap();
  class Comment {
    constructor() {
      protecteds.set(this, {
        host: '"https://ssssss.com"'
      });
    }
    set host(url) {
      if (!/^https?:/i.test(url)) {
        throw new Error("ssssss");
      }
      protecteds.set(this, { ...protecteds.get(this), url });
    }
    get host() {
      return protecteds.get(this)["host"];
    }
  }
  let a = new Comment();
  console.log(a);
  a.host = 'https://sssssssssssssssssssssssss.com'
  console.log(a.host);
  class User extends Comment {
    constructor(name) {
      super();
      this.name = name;
    }
    set name(name) {
      console.log(protecteds);
      // console.log(...protecteds.get(this));
      protecteds.set(this, { ...protecteds.get(this), name });
    }
    get name() {
      return protecteds.get(this)["name"];
    }
  }
  let ss = new User("ssssssss");
  ss.name = "ssssssssssssss";
  console.log(ss.name);
  ss.name='123123123'
  console.log();
  console.log(ss.name);

pricate私有属性使用

私有属性与私有方法

  class Common {
    #check = () => {
      if (this.name.length < 5) {
        throw new Error("名子长度不能小于五位");
      }
      return true;
    };
  }
  class User {
    //public protected private
    #host = "https://sssssssssssss.com";
    constructor(name) {
      this.name = name;
      this.#check(name);
    }
    set host(url) {
      if (!/^https?:/i.test(url)) {
        throw new Error("sssssssssss");
      }
      this.#host = url;
    }
  }
  let ss = new User("ssss");
  ss.host = "https://www.ssssssssssssss.com";
  // hd.#check();
  console.log(ss);

继承原理

方法在原型链上
属性在实例化对象上
其实就是原型链继承的语法糖

super原理

再次强调:
super就相当于this.proto
如果直接用的话还要考虑指针要用到call等

  let ss = {
    name: "ss.name",
    show() {
      // console.log(this);
      console.log(this.name);
    }
  };
  let aa = {
    __proto__: ss,
    name: "xj.name",
    show() {
      super.show();
      this.__proto__.show.call(this);
    }
  };
  aa.show();

以上两种show方法均可

在多继承中的super

多继承中只能用super
super中的this永远都是调用者的this 方法是借用的方法 就喊舒适

子类constructor中执行super、

子类中的构造函数一定要包含super且一定要在使用this之前(避免父级优先级高于子类)-不写的话系统会默认给你写一个
原因:
从原型链的角度来考虑,由于父类的赋值是在父类中使用的所以要使用父类的赋值且把this传过去,super实现了这一语法糖

使用super访问父类方法

super后什么都不跟:直接执行父类constructor
super后跟一些方法:执行父类方法

  class Common {
    sum() {
      return this.data.reduce((t, c) => t + c.price, 0);
    }
  }
  class Controller extends Common { }
  class Lesson extends Controller {
    constructor(data) {
      super();
      this.data = data;
    }
    info() {
      return {
        totalPrice: super.sum(),
        data: this.data
      };
    }
  }
  let data = [
    { name: "js", price: 100 },
    { name: "mysql", price: 212 },
    { name: "vue.js", price: 98 }
  ];
  let ss = new Lesson(data);
  console.log(ss.info());

方法的重写

  class Common {
    sum() {
      return this.data.reduce((t, c) => t + c.price, 0);
    }
    getByKey(key) {
      return this.data.filter(item => item.name.includes(key));
    }
  }
  class Controller extends Common { }
  class Lesson extends Controller {
    constructor(data) {
      super();
      this.data = data;
    }
    info() {
      return {
        totalPrice: super.sum(),
        data: this.data
      };
    }
    getByKey(key) {
      return super.getByKey(key).map(item => item.name);
    }
  }
  let data = [
    { name: "js", price: 100 },
    { name: "mysql", price: 212 },
    { name: "vue.js", price: 98 }
  ];
  let ss = new Lesson(data);
  console.log(ss.getByKey("js"));

静态继承原理

构造函数也是类 直接往里面压入方法就是静态
class用关键字实现了这一功能

  class User {
    static site = "sss.com";
    static show() {
      console.log("user.static show");
    }
  }
  class Admin extends User { }

instanceof的实现


  function checkPrototype(obj, constructor) {
    if (!obj.__proto__) return false;
    if (obj.__proto__ == constructor.prototype) return true;
    return checkPrototype(obj.__proto__, constructor);
  }

isPrototypeOf检测继承关系

与instanceof相反:
以原型对象作为主角

CLASS使用 mixin混合模式使用技巧

与正常原型链一样,原型链也是对象直接object.assign就好

  let Tool = {
    max(key) {
      return this.data.sort((a, b) => b[key] - a[key])[0];
    }
  };
  let Arr = {
    count(key) {
      return this.data.reduce((t, c) => t + c[key], 0);
    }
  };
  class Lesson {
    constructor(lessons) {
      this.lessons = lessons;
    }
    get data() {
      return this.lessons;
    }
  }
  const data = [
    { name: "js", price: 100, click: 188 },
    { name: "mysql", price: 212, click: 34 },
    { name: "vue.js", price: 98, click: 89 }
  ];
  Object.assign(Lesson.prototype, Tool, Arr);

以上是关于javaScript-你不知道的类的主要内容,如果未能解决你的问题,请参考以下文章

《你不知道的 JavaScript 上卷》 学习笔记

javaScript你不知道的闲杂知识

你不知道的Javascript:有趣的setTimeout

你不知道的JavaScript学习笔记1——作用域

你不知道的JavaScript(作用域和闭包)

你可能不知道的JavaScript代码片段和技巧(下)