ES6Class类和Symbol

Class类

在ES6中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。
class 的本质是 function。
它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。

// 构造函数
  function Person(job,name,age,sex){
   this.job = job;
   this.name = name;
   this.age = age;
   this.sex = sex;
  }
  //增加实例方法
  Person.prototype.print = function(){
   console.log('工作:',this.job)
   console.log('姓名:',this.name)
   console.log('年龄:',this.age)
   console.log('性别:',this.sex)
  }
  const a = new Person("程序猿","zhansan",30,"nan");
  a.print()
  //以前的构造函数的问题
  // 1.属性和原型方法分开了,代码可读性差
  // 2.原型上的属性也是可以枚举的
  for(const prop in a){
   console.log(prop) //job name age sex print
  }
  //3.构造函数也是可以当成普通函数使用的

// ES6中
// 从逻辑上说更合理,成为一个整体
// console.log(Person)   //临时性死区
  class Person{
   constructor(job,name,age,sex){
    this.job = job;
    this.name = name;
    this.age = age;
    this.sex = sex;
   }
   print(){
    console.log('工作:',this.job)
    console.log('姓名:',this.name)
    console.log('年龄:',this.age)
    console.log('性别:',this.sex)
   }
  }
  const a = new Person("程序猿","zhansan",30,"nan");
  console.log(a) 
  a.print()
  // 1.类的声明不会被提升,和let const 一样,有临时性死区
  // 2.类的所有代码全都是在严格模式中执行
  // 3.类的所有方法都是不可枚举的
  for(const prop in a){
  	console.log(prop) //job name age sex
	}
  // 4.类的所有方法都无法当成构造函数直接使用
  // const b = new a.print()
  // 5.类的构造器必须使用new 来调用
  const b = Person("程序猿","zhansan",30,"nan"); //报错

1.可以写成计算属性名

  const printName = "print";
  const test = "job1"
  class Person{
   constructor(job,name,age,sex){
    this[test] = job;
    this.name = name;
    this.age = age;
    this.sex = sex;
   }
   [printName](){
    console.log('工作:',this[test])
    console.log('姓名:',this.name)
    console.log('年龄:',this.age)
    console.log('性别:',this.sex)
   }
  }
  const a = new Person("程序猿","zhansan",30,"nan");
  console.log(a)
  a[printName]()

2.可以使用getter 和 setter
getter取值的时候必须走进来 get
setter 设置值得之后必须走进来 set
getter 不可单独出现
getter 与 setter 必须同级出现
get set 控制的属性不在原型上

ES5的写法
 Object.defineProperty(this,"age", {
 set(age){
},
 get(){
 }
  })

ES6的写法

const printName = "print";
  const test = "job1"
  class Person{
   constructor(job,name,age,sex){
    this[test] = job;
    this.name = name;
    this.age = age;
    this.sex = sex;
   }
   get age(){  //取值的时候走  没有参数
    return this._age + "岁";
   }
   set age(age){  //创建的时候进来,必须接受一个参数
    if(typeof age !== "number"){
     throw new TypeError("age must a number")
    }
    if(age < 0){
     age = 0
    }else if(age > 200){
     age = 200
    }
    this._age = age;
   }
   [printName](){
    console.log('工作:',this[test])
    console.log('姓名:',this.name)
    console.log('年龄:',this.age)
    console.log('性别:',this.sex)
   }
  }
  const a = new Person("程序猿","zhansan",-10,"nan");
  console.log(a)
  a[printName]()

3.静态成员 static

class Qi{
   constructor(name,width,height){
    this.name = name;
    // this.width = width;
    // this.height = height;
   }
   static width = 50;   //添加静态成员
   static height = 50;
   static method = function(){}
  }
  const ma = new Qi("马",50,50);
  const pao = new Qi("炮",50,50);
  console.log(ma.width)  //undefined
  console.log(pao) //Qi {name: "炮"}
  console.log(Qi.width) //50

4.字段初始器(es7)

class Test{
   a = 1;  //初始化的工作,如果没有使用static,就是实例成员
   b = 2;
   static c = 3
   // constructor(){
   //  this.a = 1;
   //  this.b = 2
   // }
   print = () => {    //不会存放在原型上面,会占用一定的存储空间
    console.log(this.a)
   }
  }
  const t = new Test()
  const g = new Test()
  console.log(t)  //Test {a: 1, b: 2, print: ƒ}
  console.log(t.a,t.b,t.c,Test.c) //1 2 undefined 3
  // 1.使用static添加字段初始器,添加的是静态成员
 // 2.没有使用,则位于对象上
 // 3.箭头函数在字段初始器位置上,指向当前对象
  t.print() //1
  console.log(t.print == g.print) //false

5.类表达式

  const A = class{   //匿名类,类表达式,类在js中本身就是表达式
   a = 1;
   b = 2;
  }
  const a = new A();
  console.log(a)  // A {a: 1, b: 2}

6.类的继承
extends 继承,用于类中的定义
class Child extends Father { ... }
super
子类 constructor 方法中必须有 super ,且必须出现在 this 之前。
1.直接当成函数调用,表示父类的构造

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}`)
   }
  }
  class Dog extends Animal{
   // 如果定义了constructor 并表示这个是子类,则必须在constructor的第一行手动调用父类的构造函数
   // constructor(name,age,sex){
    // super ("犬类",name,age,sex)
   // }
   // 如果说子类不写constructor,则会有默认的构造器,自动去调用父类的构造器
  }
  const d = new Dog("犬类","旺财",5,"公");
  console.log(d);
  d.print();

2.super如果说当成对象使用,则表示父类的原型

class Dog extends Animal{
   constructor(name,age,sex){
    super("犬类",name,age,sex);
    this.loves = "吃骨头"
   }
   print(){   //同名的方法会进行覆盖
    // console.log("wang")
   //2.super如果说当成对象使用,则表示父类的原型
    super.print();
    console.log(`爱好 : ${this.loves}`)
   }
  }
  const d = new Dog("旺财",5,"公");
  console.log(d);
  d.print();

Symbol

ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
ES6 数据类型除了 Number 、 String 、 Boolean 、 Objec t、 null 和 undefined ,还新增了 Symbol 。
创建

  const syb1 = Symbol();   //创建了一个符号
  const syb2 = Symbol("asdfsdf");
  // 就是一个新增数据类型  
  console.log(syb1,syb2) //Symbol() Symbol(asdfsdf)
  console.log(typeof syb1)  //symbol

特点
1.没有字面量的写法
2.新的数据类型,typeof返回的是symbol
3.每次去调用Symbol函数得到的符号永远不会相等,不管符号描述是否相同

const syb1 = Symbol("abc");   
const syb2 = Symbol("abc");
console.log(syb1,syb2) //Symbol(abc) Symbol(abc)
console.log(syb1 === syb2) //false

4.符号可以作为对象的属性名使用,这种属性名叫符号属性

const syb1 = Symbol("abc");  
  const obj = {
   a : 1,
   b : 2,
   [syb1] : 3    //符号属性
  }
  console.log(obj)

5.可以通过设计,让外面无法访问到

const Hero = (() =>{
   const getRandom = Symbol()   //计算属性名
   return class{
    constructor(attack,hp,defence){
     this.attack = attack;
     this.hp = hp;
     this.defence;
    }
    gongji(){
     const dmg = this.attack * this.getRandom(0.7,1.2)
    }
    [getRandom](min,max){
     return Math.random() * (max - min) + min
    }
   }
  })()
  const h = new Hero(3,100,3)
  console.log(h)

6.符号属性不能被枚举

const syb1 = Symbol("abc");  
  const obj = {
   a : 1,
   b : 2,
   [syb1] : 3    //符号属性
  }
  console.log(obj) //["a", "b"]
  for(const prop in obj){
   console.log(prop) //["a", "b"]
  }
  console.log(Object.keys(obj))   //es5获取属性名的方法也不行
  console.log(Object.getOwnPropertyNames(obj))   //ES6方法也不能获取属性名
  // 针对符号属性
  // getOwnPropertySymbols(obj)
  // console.log(Object.getOwnPropertySymbols(obj))   [Symbol(abc)]
  const sybs = Object.getOwnPropertySymbols(obj)[0]; 
  console.log(sybs == syb1) //true

7.符号类型无法被隐式转换,数学运算,字符串拼接都是不行的
可以进行内部的显式转换 console.log的输出

const syb = Symbol();
console.log(syb + 10) 

Symbol.for()
共享符号
Symbol.for(“符号描述”) 如果符号描述相等,则可以得到同一个符号

const syb1 = Symbol.for("abc");   
  const syb2 = Symbol.for("abc");
  console.log(syb1,syb2) //Symbol(abc) Symbol(abc)
  console.log(syb1 === syb2) //true
const obj = {
   a : 1,
   b : 2,
   [Symbol.for("c")] : 3
  }
  console.log(obj)  //{a: 1, b: 2, Symbol(c): 3}
  console.log(obj[Symbol.for("c")]) //3

特殊含义的共享符号 通过Symbol的配置得到的
JavaScript 松散,写法不严谨
必须去解决这些严谨性的问题
配置底层的实现原理
1.Symbol.hasInstance
用于判断某对象是否为某构造器的实例。 因此你可以用它自定义instanceof操作符在某个类上的行为。

function A(){}
  // const obj = new A();
  // console.log(obj instanceof A) // true 
  // console.log(A[Symbol.hasInstance](obj));  // true 不能这种方式配置
  Object.defineProperty(A,Symbol.hasInstance,{
   value : function(obj){
    console.log(obj);
    return false;
   }
  })
  const obj = new A();
  console.log(obj instanceof A)    // false 可以去改变instanceof 的值

2.Symbol.isConcatSpreadable
用于配置某对象作为Array.prototype.concat()方法的参数时是否展开其数组元素。
会对数组的方法产生影响
对于数组对象,默认情况下,用于concat时,会按数组元素展开然后进行连接(数组元素作为新数组的元素)重置Symbol.isConcatSpreadable可改变默认行为。
对于类似数组的对象,用于concat时,该对象整体作为新数组的元素,重置Symbol.isConcatSpreadable可改变默认行为。

// 设置Symbol.isConcatSpreadable为false
  const arr1 = [3];
  const arr2 = [4,5,6,7]
  arr2[Symbol.isConcatSpreadable] = false;
  const resul = arr1.concat(99,arr2)   //对两个数组拆分链接成新的数组
  console.log(resul) // [3, 99, Array(4)]
  // 默认情况下
  const arr = [1];
  const obj = {
   0 : 3,
   1 : 5,
   length : 2,
   [Symbol.isConcatSpreadable] : true
  }
  const result = arr.concat(99,obj)
  console.log(result) //[1, 99, 3, 5]

3.Symbol.toPrimitive
作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。

const obj = {
   a : 1,
   b : 2
  }
  obj[Symbol.toPrimitive] = function(){
   return 123
  }
  console.log(obj + 123) //246

4.Symbol.toStringTag
该Symbol.toStringTag公知的符号是在创建对象的默认字符串描述中使用的字符串值属性。它由该Object.prototype.toString()方法在内部访问。 可以影响Object.prototype.toString的返回值

class Person{
   [Symbol.toStringTag] = "Person"
  }
  const p = new Person()
  console.log(p)
  const arr = [12,1,2]
  console.log(Object.prototype.toString.call(p)) //[object Person]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值