es6 class类

class Point{
}
target:掌握es6的class
相当于es5的语法糖 基于在函数的原型链(需要掌握js的继承和原型链的定义)
默认严格模式且不存在变量提升
toString 在es5上可以被枚举 Object.keys 但是在es6上不可以 因为它是定义在prototype上的property。
constructor 在class类中默认会添加 方法默认返回this实例对象
实例化class 必须使用new 否则报错
实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上) 可以用hasOwnProperty 验证 proto不是语言本身的特性 可以使用Object.getPrototypeOf() 方法获取实例的原型 然后用Object.assign()为原型添加方法或者属性

实例之后的对象 公用一个原型对象 于es5一样

取值函数(getter)和存值函数(setter)
get 和 set 函数是设置在属性的Descriptor上的 可以用Object.getOwnPropertyDescriptor()调用
如果有相同名称的普通函数 会覆盖get和set函数 使用Object.assign()给类添加同名的函数 不会覆盖

类可以用定义变量来命名

let methodName = 'getArea';

class Square {
  constructor(length) {
    // ...
  }

  [methodName]() {
    // ...
  }
}

Generator方法
如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数。

(重点)this指向问题 默认指向类的实例

举例

class Logger {
  printName(name = 'there') {
    this.print(`Hello ${name}`);
  }

  print(text) {
    console.log(text);
  }
}

const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined

文中 print的this指向该方法运行所在的环境 即全局 所以会报错
这种情况可以在constructor中 bind(this)或者箭头函数来绑定this

静态方法

类为es5的基础上创建的语法糖 相当于实例的原型 都会被实例继承
加上static 关键字 表示该方法不会被实例继承 而是直接通过类来调用 这就是'静态方法'

class Foo {
  static classMethod() {
    return 'hello';
  }
  static bar() {
    this.baz();
  }
  static baz() {
    console.log('hello');
  }
  baz() {
    console.log('world');
  }
}

Foo.classMethod() // 'hello'
Foo.bar() // hello

var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function

如果静态方法中包含this关键字 那么这个this指向的是类 而不是实例
静态方法也可以和非静态方法重名

静态方法虽然不可以实例继承 但是可以被子类继承 而且静态方法也是可以从super对象上调用

class Foo {
  static classMethod() {
    return 'hello';
  }
}

class Bar extends Foo {
  static classMethod() {
    return super.classMethod() + ', too';
  }
}

Bar.classMethod() // // "hello, too"

静态属性 指的是class本身的属性 而不是定义在实例对象(this)上的属性

class Foo {
}

Foo.prop = 1;
Foo.prop // 1

新的定义静态属性的提案

class MyClass {
  static myStaticProp = 42;

  constructor() {
    console.log(MyClass.myStaticProp); // 42
  }
}
实例属性的新写法 除了在constructor里面以外也可以写在类的顶层
class IncreasingCounter {
  _count = 0;
  get value() {
    console.log('Getting the current value!');
    return this._count;
  }
  increment() {
    this._count++;
  }
}
私有属性的提案

带(#)

new.target 属性

用在构造函数之中 如果构造函数不是通过new命令调用的 new.target会返回undefined 因此这个属性可以用来确定构造函数是怎么调用的。

class Shape {
  constructor() {
    if (new.target === Shape) {
      throw new Error('本类不能实例化');
    }
  }
}

class Rectangle extends Shape {
  constructor(length, width) {
    super();
    // ...
  }
}

var x = new Shape();  // 报错
var y = new Rectangle(3, 4);  // 正确
class继承

子类自己的this对象必须先通过父类的构造函数完成塑造 所以子类必须再constructor方法中调用super方法
所以只有再super()之后才可以调用this关键字
父类的静态方法也会被子类继承
Object.getPrototypeOf() 可以用来从子类上获取父类
super 关键字可以用来当作对象和函数使用
当super当作函数的时候 this关键字 指向子类 因为super在子类是通过父类的构造函数完成塑造和子类this的绑定 相当于Point.prototype.constructor.call(this)
当super当作对象时 指向父类的原型对象 定义在prototype上则可以取到
在静态方法中 指向父类 在父类实例上的方法或者property 是无法通过super调用的

在子类普通方法中 super调用父类方法的时候 方法内部的this指向当前的子类的实例 说白了就是函数作用域
因为super() this关键字指向子类实例 所以如果通过super对某个属性赋值 赋值的属性会变成子类实例的属性

如果super作为对象 用在静态方法中 super指向父类 而不是父类的原型 因为静态方法本身就是类的直接调用
所以同样的道理 如果在子类的静态方法中存在this 那么这个this指向子类本身而不是子类的实例

使用super的时候 必须显式指定是作为函数还是作为对象使用,否则会报错
对象总是继承其他对象的 所以可以在任意一个对象中 使用super关键字

class Point{
    constructor(){
        this.p = 2  
    }
    print(){
       console.log(this.p)
   }
}

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y)
    this.color = color;
    this.p = 3
  }

  toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
  }
  static m(){
      super.print();// 静态方法中的this指向子类本身 而不是子类的实例  举例:ColorPoint.p = 3 则ColorPoint.m() //3 静态方法不可以实例化调用 应该为类的本身调用
  }
  m(){
    super.print();
  }
}
let b = new ColorPoint()
b.m()//undefined
//如果加上Point.prototype.p = 2;
b.m() //2
//如果加上 子类this.p = 3
b.m() //3
类的prototype属性和proto属性

这个是子类和父类之间继承的原型链

每个对象都有proto属性 指向对应构造函数的prototype属性 class作为构造函数的语法糖 同时有prototype属性和proto属性 因此同时存在两条继承链
子类的proto属性表示构造函数的继承 总是指向父类
子类的prototype属性的proto属性 表示方法的继承,总是指向父类的prototype属性

class A {
}

class B {
}

// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);

// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);

const b = new B();、
//Object.setPrototypeOf 方法的实现
Object.setPrototypeOf = function (obj, proto) {
  obj.__proto__ = proto;
  return obj;
}

//所以
Object.setPrototypeOf(B.prototype, A.prototype);
// 等同于
B.prototype.__proto__ = A.prototype;

Object.setPrototypeOf(B, A);
// 等同于
B.__proto__ = A;


Object.create(A.prototype);
// 等同于
B.prototype.__proto__ = A.prototype;

只要A是一个有prototype属性的函数 就能被B继承 但是由于函数都有prototype属性 所以A可以是任意函数

class A extends Object {
}

A.__proto__ === Object // true
A.prototype.__proto__ === Object.prototype // true

如果不存在继承的情况

class A {
}

A.__proto__ === Function.prototype // true
A.prototype.__proto__ === Object.prototype // true

原生构造函数的继承

原生构造函数是指语言内置的构造函数 通常用来生成数据结构
Boolean()
Number()
String()
Array()
Date()
Function()
RegExp()
Error()
Object()

function MyArray() {
  Array.apply(this, arguments);
}

MyArray.prototype = Object.create(Array.prototype, {
  constructor: {
    value: MyArray,
    writable: true,
    configurable: true,
    enumerable: true
  }
});
var colors = new MyArray();
colors[0] = "red";
colors.length  // 0

colors.length = 0;
colors[0]  // "red"

用原本的es5的继承会出现这种情况的原因是因为 子类无法获得原生构造函数的内部属性 通过Array.apply()或者分配给原型对象都不行 原生构造函数会忽略apply方法传入的this 也就是说 原生构造函数的this无法绑定,导致拿不到内部属性

es6 允许继承原生构造函数定义子类 因为es6是先新建父类的实例对象 this 然后在用子类的构造函数 修饰this 使得父类的所有行为都可以继承

class MyArray extends Array {
  constructor(...args) {
    super(...args);
  }
}

var arr = new MyArray();
arr[0] = 12;
arr.length // 1

arr.length = 0;
arr[0] // undefined

这个例子也说明 extends关键字不仅可以用来继承类 还可以用来继承原生的构造函数

Mixin 模式的实现

Mixin指的是 多个对象合成一个新的对象 新对象具有各个组成成员的接口 它的最简单实现方式

const a = {
  a: 'a'
};
const b = {
  b: 'b'
};
const c = {...a, ...b}; // {a: 'a', b: 'b'}
//c对象是a对象和b对象的合成,具有两者的接口。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容