zoukankan      html  css  js  c++  java
  • ES6——class类继承(读书笔记)

    前言

      我一定是一个傻子,昨天这篇文章其实我已经写好了一半了,但是我没有保存

      这是学习ES6的过程,我没有系统的看完阮大大的书。零零散散的,很多功能知道,但是没有实际的用过

      看了几遍,总是看前面几章,所以这次我要立下flag 一定从头到尾学一遍ES6(有点讽刺 现在好像都有ES9了)

      ES5与ES6 相差还是很大的

    一、类

      ES5 没有类这个说法,但是是可以实现类这样功能的,那就是构造函数 

    function Point (x,y){
      this.x = x
      this.y = y    
    }
    
    var a  = new Point(1,2)
    console.log(a.x) //1

      然后我在mdn上找到一个例子 详细的说了构造函数的原型 原型链

      

    // 让我们从一个自身拥有属性a和b的函数里创建一个对象o:
    let f = function () {
       this.a = 1;
       this.b = 2;
    }
    /* 这么写也一样
    function f() {
      this.a = 1;
      this.b = 2;
    }
    */
    let o = new f(); // {a: 1, b: 2}
    
    // 在f函数的原型上定义属性
    f.prototype.b = 3;
    f.prototype.c = 4;
    
    // 不要在 f 函数的原型上直接定义 f.prototype = {b:3,c:4};这样会直接打破原型链
    // o.[[Prototype]] 有属性 b 和 c
    //  (其实就是 o.__proto__ 或者 o.constructor.prototype)
    // o.[[Prototype]].[[Prototype]] 是 Object.prototype.
    // 最后o.[[Prototype]].[[Prototype]].[[Prototype]]是null
    // 这就是原型链的末尾,即 null,
    // 根据定义,null 就是没有 [[Prototype]]。
    
    // 综上,整个原型链如下: 
    
    // {a:1, b:2} ---> {b:3, c:4} ---> Object.prototype---> null
    
    console.log(o.a); // 1
    // a是o的自身属性吗?是的,该属性的值为 1
    
    console.log(o.b); // 2
    // b是o的自身属性吗?是的,该属性的值为 2
    // 原型上也有一个'b'属性,但是它不会被访问到。
    // 这种情况被称为"属性遮蔽 (property shadowing)"
    
    console.log(o.c); // 4
    // c是o的自身属性吗?不是,那看看它的原型上有没有
    // c是o.[[Prototype]]的属性吗?是的,该属性的值为 4
    
    console.log(o.d); // undefined
    // d 是 o 的自身属性吗?不是,那看看它的原型上有没有
    // d 是 o.[[Prototype]] 的属性吗?不是,那看看它的原型上有没有
    // o.[[Prototype]].[[Prototype]] 为 null,停止搜索
    // 找不到 d 属性,返回 undefined

      看完这个例子,就大概知道原型 原型链 是怎样一层一层的找的(又有灵感 写一篇古风版的原型链了)

      然后ES6 是怎么样的呢

    class Point{
            constructor(x,y){
                this.x = x;
                this.y = y;
          }
        toString(){
            return "("+this.x+","+this.y+")"
        }
    }           

     上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法 

       而this关键字则代表实例对象。也就是说,ES5 的构造函数Point,对应 ES6 的Point类的构造方法。

     使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。

    class Bar {
      doStuff() {
        console.log('stuff');
      }
    }
    
    var b = new Bar();
    b.doStuff() // "stuff"

     类的所有方法都定义在类的prototype属性上面。(继承) 在类的实例上面调用方法,其实就是调用原型上的方法。

    class B {}
    let b = new B();
    
    b.constructor === B.prototype.constructor // true

      prototype对象的constructor属性,直接指向“类”的本身,这与 ES5 的行为是一致的。

     Point.prototype.constructor === Point // true

    toString方法是Point类内部定义的方法,它是不可枚举的。这一点与 ES5 的行为不一致。

    constructor方法

      constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。

    class Point {
    }
    
    // 等同于
    class Point {
      constructor() {}
    }
    1. 类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行
    2. constructor函数返回一个全新的对象,结果导致实例对象不是Foo类的实例。
    3. class Foo {
        constructor() {
          return Object.create(null);
        }
      }
      
      new Foo() instanceof Foo
      // false
    4. 类不存在变量提升(hoist),这一点与 ES5 完全不同。
    5. {
        let Foo = class {};
        class Bar extends Foo {
        }
      }

      上面的代码不会报错,因为Bar继承Foo的时候,Foo已经有定义了。但是,如果存在class的提升,上面代码就会报错,因为class会被提升到代码头部,而let命令是不提升的,所以导致Bar继承Foo的时候,Foo还没有定义。

    6. 由于本质上,ES6 的类只是 ES5 的构造函数的一层包装,所以函数的许多特性都被Class继承,包括name属性  name属性总是返回紧跟在class关键字后面的类名。
      class Point {}
      Point.name // "Point"
    7. 如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数。
    8. class Foo {
        constructor(...args) {
          this.args = args;
        }
        * [Symbol.iterator]() {
          for (let arg of this.args) {
            yield arg;
          }
        }
      }
      
      for (let x of new Foo('hello', 'world')) {
        console.log(x);
      }
      // hello
      // world

      上面代码中,Foo类的Symbol.iterator方法前有一个星号,表示该方法是一个 Generator 函数。Symbol.iterator方法返回一个Foo类的默认遍历器,for...of循环会自动调用这个遍历器。

    9. 在构造方法中绑定this,这样就不会找不到print方法了。 不然就会this会指向该方法运行时所在的环境(由于 class 内部是严格模式,所以 this 实际指向的是undefined),从而导致找不到print方法而报错。
    10. 另一种解决方法是使用箭头函数。
    11. class Obj {
        constructor() {
          this.getThis = () => this;
        }
      }
      
      const myObj = new Obj();
      myObj.getThis() === myObj // true

    二、静态方法

      类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

      

    class Foo {
      static classMethod() {
        return 'hello';
      }
    }
    
    Foo.classMethod() // 'hello'
    
    var foo = new Foo();
    foo.classMethod()
    // TypeError: foo.classMethod is not a function

      

  • 相关阅读:
    Linux基础命令(一)
    You've made choice
    protege推理
    字符编码
    第二次作业
    数据类型-集合set
    数据类型-元组&字典
    数据类型-列表
    数据类型-数值&字符串
    流程控制之for循环
  • 原文地址:https://www.cnblogs.com/ifannie/p/11091532.html
Copyright © 2011-2022 走看看