class

我们用class来定义一个函数,不在简简单单的使用function,好歹也应该让自己装装逼了eg:

class A {
  //   构造方法
  constructor(name) {
    this.name = name; // 当使用new A()的时候回触发该构造方法,该方法可以有参数,参数便是在进行new操作构造函数时传递的参数
  }
  //   定义的实例方法
  sayHello() {
    console.log("my name is: " + this.name);
  }
  //   重写toString方法
  toString() {
    return this.name;
  }
  //这内部的方法就好比是在方法A的原型上添加的方法A.prototype.toString等等
}
var a = new A("jack"); // 将调用A中的constructor方法
a.sayHello(); // "my name is: jack"
console.log(a.toString()); // "jack" 可以调用上面A类下的方法
console.log(typeof A); // "function" A同样是一个function方法
console.log(A === A.prototype.constructor); // true A的原型prototype的constructor指向函数本身A
console.log(a.constructor === A.prototype.constructor); // true 实例的构造方法就是A类原型上的constructor。
console.log(Object.keys(A.prototype)); // [] 通过class这种方式定义的构造方法,其内部定义的所有实例方法都是不可枚举的
A.prototype.tell = () => {}; // 通过prototype重写toString方法,在ES5中是可枚举的
console.log(Object.keys(A.prototype)); // ["tell"] 可以之后通过prototype来定义的方法或属性可以遍历到
console.log(Object.getOwnPropertyNames(A.prototype));
// ["constructor", "sayHello", "toString", "tell"] 通过getOwnPropertyNames能获取到定义在类A中的所有属性名
let phone = "myPhone";
class A {
  constructor(phone) {
    this.phone = phone;
  }
  // 通过变量表达式来定义方法
  [phone]() {
    return this.phone;
  }
}
let a = new A(110);
//调用表达式定义的方法
console.log(a[phone]()); // 110

考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式
//每个class类中都会有一个constructor构造方法,若没有显示提供该方法,则程序会默认在该类中添加一个空的constructor构造方法,并且在new操作的时候会主动调用该构造方法

class A {
  constructor(name) {
    return Object.create(null); // 返回了一个全新的对象
  }
}
console.log(new A() instanceof A); // false
A(); // 直接以函数的形式调用会报错 TypeError: Class constructor A cannot be invoked without 'new'

constructor可以指定返回值,但是当指定返回值后会导致A的实例通过instanceof来判断返回false,当constructor没有返回值的时候,将默认返回实例对象this

class A {
  constructor(name) {
    this.name = name; // 只有通过this显示的定义属性,会在自身上,否则都将是在prototype原型上
  }
  toString() {
    return this.name;
  }
}
let a = new A("张三");
console.log(a.name); // "张三"
console.log(a.hasOwnProperty("name")); // true
console.log(a.hasOwnProperty("toString")); // false
console.log(a.__proto__.hasOwnProperty("toString")); // true
let b = new A("李四");
console.log(a.__proto__ === b.__proto__); // true a,b都是A的实例对象,他们的原型都是A.prototype
//当在其中一个实例对象上的__proto__添加方法,则该方法便是添加在类A的原型prototype上,故而所有实例将会共享该方法
a.__proto__.sayName = function() {
  console.log(this.name);
};
a.sayName(); // "张三"
b.sayName(); // "李四"

只有显示定义在this上的属性都是实例对象自身的属性,其他定义的都将会通过原型去查找,同一个类构建出来的实例共享同一个原型对象

//通过表达式来定义class 其中类名应为A a只能是在类内部使用,相当于是匿名函数中的函数名
const A = class AA {
  // 使用别名a来代指该类 返回该方法名
  sayName() {
    return AA.name;
  }
};
let a = new A();
console.log(a.sayName()); // "AA"
console.log(AA.name); // AA is not defined

// ES5 就如下方式
const A = function AA() {};
A.prototype.sayName = function() {
  return A.name;
};

let a = new A();
console.log(a.sayName()); // "AA"
// 在定义时便执行了,相当于函数自执行方式
let a = new class A {
  constructor(name) {
    this.name = name;
  }
  sayName() {
    return this.name;
  }
}("张三");

console.log(a.sayName()); // "张三"
//属性私有性
class A {
  // 公有方法
  f(baz) {
    this._bar(baz);
  }
  // 私有方法
  _bar(baz) {
    return (this.b = baz);
  }
}
let a = new A();
// 通过公有方法调用给值b赋值
a.f("b");
console.log(a.b); // "b"

// 实例a同样还是能够直接调用到_bar私有方法
a._bar("b");
console.log(a.b); // "b"

class A {
  // 公有方法,通过call方法调用外部函数,使得实例无法直接调用来达到直接赋值操作
  f(baz) {
    bar.call(this, baz);
  }
}
function bar(baz) {
  return (this.b = baz);
}
let a = new A();
a.f("b");
console.log(a.b); // "b"
// 还有种方式是将私有方法名以表达式的形式定义为Symbol值 eg:
const bar = Symbol("bar");
const b = Symbol("b");
class A {
  // 公有方法
  f(baz) {
    this[bar](baz);
  }
  //   私有方法
  [bar](baz) {
    this[b] = baz;
  }
}
let a = new A();
// 调用公有方法
a.f("b");
console.log(a[b]); // "b"
class A {
  init(name = "张三") {
    //   调用sayHello方法
    this.sayHello(`hello ${name}`);
  }
  sayHello(text) {
    console.log(text);
  }
}
let a = new A();
// 正常调用
a.init(); // "hello 张三"
// 赋值调用时
let { init } = a;
init(); // TypeError: Cannot read property 'sayHello' of undefined 

此时this指向的是该方法的运行环境,此时在方法中this为undefined,故而无法找到sayHello方法,注意,只有在严格模式下this的值才有可能为undefined,在ES6中,使用class的方式,都是属于严格模式。
// 还有种方式,在定义constructor构造函数的时候就固定this eg:


class A {
  // 在构造函数这儿将调用有使用到this的方法绑定this指向到A
  constructor() {
    this.init = this.init.bind(this);
  }
  init(name = "张三") {
    //   调用sayHello方法
    this.sayHello(`hello ${name}`);
  }
  sayHello(text) {
    console.log(text);
  }
}
let a = new A();
let { init } = a;
init(); // "hello 张三"
通过箭头函数的方式来固定this指向
class A {
  constructor() {
    //   通过箭头函数来固定this的指向,在箭头函数里,this的指向是定义时就固定了的
    this.init = (name = "张三") => {
      this.sayHello(`hello ${name}`);
    };
  }
  sayHello(text) {
    console.log(text);
  }
}
let a = new A();
let { init } = a;
init(); // "hello 张三"
 通过setter及getter来存取值 class A {
  get f() {
    return "getter";
  }
  set f(val) {
    console.log("setter: " + val);
  }
}
let a = new A();
a.f = "hello"; // "setter: hello" 设置值
console.log(a.f); // "getter" 取值
target new操作时,target会指向该类,若是继承的情况,将指向子类
class A {
  constructor() {
    console.log(new.target === A); // true
    // 当有继承关系时,将返回的是子类。
    console.log(new.target); // "[(Function: B)]"
  }
}
class B extends A {
  constructor() {
    super();
  }
}
let b = new B();
百度已收录
分享