ES6 -- class学习(1)

1.class简介

  • 1.1 javascript 语言的传统方法是通过构造函数定义并生成新对象。下面是一个例子

      {
          function Point(x, y){
              this.x = x;
              this.y = y;
          }
    
         Point.prototype.sum = function(){
             console.log(this.x + this.y)
         } 
    
         let p = new Point(1,2);    
         p.sum();
         //3
     }
    
  • 1.2 ES6采用Class关键字来定义类

     {
          class Point {
              constructor(x,y){
                  this.x = x;
                  this.y = y;
              }
    
              sum(){
                  console.log(this.x + this.y)
                  return (this.x + this.y)
              }
          }
    
          let p2 = new Point(2,3);
          p2.sum();
          //5
     }
    
     上面的代码定义了一个“类”,可以看到里面有一个constryctor方法,这就是构造方法,this关键字代表实例对象
     还定义了一个sum求和方法
    
  • 1.3 注意

     {
         class Point2 {
             //...
         }
    
         console.log(typeof Point2);   //function
         console.log(Point2 === Point2.prototype.constructor);
         //true
     }
     上面代码表明,类的数据类型就是函数,类本身就指向构造函数。
     使用的时候也是直接使用new命令,和构造函数的用法一致。
    
  • 1.4构造函数的prototype属性在ES6的“类”上继续存在。事实上,类的所有方法都定义在类的prototype属性上。

      {
      class Point {
          constructor(){
              //...
          }
    
          toString(){
              //...
          }
    
          toValue(){
              //....
          }
      }
    
      // 等同于添加到Point的prototype属性上
    
      Point.prototype = {
          constructor() {},
          toString() {},
          toValue() {}
      }
    
      //由于类的方法(constructor除外)都定义在prototype对象上,所以类的新方法可以添加在prototype对象上
      // Object.assign 方法可以很方便的一次向类添加多个方法。
    
      class Point {};
      Object.assign(Point.prototype,{
          toString(){},
          toValue(){}
      })
    

    }

  • 1.5 在类的实例上调用方法,实际上就是调用原型上的方法。

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

    }

2.contructor方法

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

{
    class Point {}

    => 等同于

    class Point {
        constructor (){}
    }
}

3.类的实例对象

class命令生成实例对象的语法和ES5一样,也是使用new命令
{
    class Point {}

    let p = new Point();
}

这点与ES5一样,实例的属性除非显示定义在其本身(this对象)上,否则都是定义在原型(class)上。
{
        //定义类
        class Point {
            constructor(x,y){
                this.x = x;
                this.y = y;
            }

            toSum(){
                console.log(this.x + this.y);
            }

        }

        let p = new Point(2,3);

        let p2 = new Point(1,2);

        p.toSum();
        // /5

        console.log(p.hasOwnProperty('x'));
        //true
        console.log(p.hasOwnProperty('y'));
        //true
        console.log(p.hasOwnProperty('toSum'));
        //false

        console.log(p.__proto__ === p2.__proto__);
        //true
        //所有的实例对象都共享一个原型对象
    }

    // 因为定义在this变量上,所以x,y是p本身的属性,而toSum则是原型对象的属性。

4.class表达式

{
        let myClass = class {
            constructor(){
                console.log('123');
            }
        }

    }

5.calss不存在变量提升

{
        new Foo();  
        //ReferenceError
        class Foo {}
    }

    // 上面的代码中,Foo类使用在前,定义灾后,这样会报错,因为ES6不会把变量声明替身到代码头部。
    // 这与下文要提到的继承有关,必须保证子类在父类之后定义

    {
        let Foo = class {};
        class Bar extends Foo {};
    }

    // 上述代码不会报错,是因为Bar在继承Foo的时候,Foo已经声明了。如果存在class提升,那样Bar继承时Foo还没有定义就会报错

6.私有方法和私有属性

     私有方法是常见需求,但是ES6不提供,只能通过变通的方法来模拟实现。

    在命名上加以区别
    {
        class Widget {
            //公有方法
            foo(){
               console.log('something'); 
            }

            //私有方法
            _bar() {
                console.log('nothing');
            }
        }
    }
    但是这种方法并不保险,在类的外部依旧可以调用这个方法。


    将私有方法一处模块,因为模块内部所有方法是对外可见的
    {
        class getSomething {
            getWidth(height){
                getHeight.call(this,height)
            }
        }

        function getHeight(height){
            this.height = height;
            console.log(height);
        }

        let b = new getSomething();
        b.getWidth('100px');
        b.getHeight();
        //b.getHeight is not a function
    }

    这使得getHeight成为当前模块的私有方法

    利用symbol值的唯一性将私有方法得名字命名为一个symbol值
    {
        let bar = Symbol('bar');
        let snaf = Symbol('snaf');

        class myClass {
            //公有方法
            foo(baz) {
                this[bar](baz)
            }

            //私有方法
            [bar](baz) {
                 this[snaf] = baz;
                 console.log(this[snaf]);
            }
        }

        let p2 = new myClass();
        p2.foo('123');
    }

    因为Object.getOwnPropertySymbols() 的出现,基本可以认为是私有变量和私有属性

7.this指向

类的方法内部如果含有this,他将默认指向类的实例.但是必须非常小心,一旦单独使用该方法,很可能会报错.

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

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

        const p = new Logger();
        p.printName();
        //hello threr

        p.print(123);
        //123

        const { printName } = p;
        printName();//报错
    }

    上面的代码中,printName方法中的this默认指向Logger的实例,但是吐过将这个方法取出来单独使用,this指向该方法
    运行时所在的环境,因为找不到print方法报错.

    1.在构造函数方法中绑定this,这样不会报错了
    {
        class Logger2 {
            constructor(){
                this.printName = this.printName.bind(this);
            }
            printName(name = 'there') {
                this.print(`Hello ${name}`);
            }

            print(text){
                console.log(text);
            }
        }
        const p = new Logger2();

        const { printName } = p;
        printName();
        //hello there
    }


    2.使用箭头函数
    
    {
        class Logger {
            constructor(){
                this.printName = (name = 'there') => {
                    this.print(`hello ${name}`)
                }
            }

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

        const p = new Logger();
        const { printName } = p;
        printName();
        //hello there
    }

8.name 属性

{
class Point {}
Point.name
//Point

name 属性返回紧跟在calss关键字后面的类名

}

9.class静态方法

类相当于实例的原型,所有在类中定义的方法都会被实例继承.如果这个方法时静态方法,就不会被继承.

 {
        class Foo {
            static sum(a,b)
            {
                console.log(a + b);
            }
        }

        let p = new Foo();
        // p.sum(2,3);
        //报错

        Foo.sum(1,2);
        //3

        class Bar extends Foo {}
        Bar.sum(19,2);
        //21
    }

    // 因为类Foo时static关键字定义的,所以属于静态方法,所以实例不能继承,但是父类可以调用
    //子类也可以通过继承类使用父类的静态方法

10.class的静态属性和实例属性

  • ES6明确规定class内部只有静态方法,没有静态属性
    

    只能这样声明静态属性
    {
    class Foo {}

      foo.name = 'kjh'
      Foo.name 
      //kjh
    

    }

    或者{
    class Foo {
    static name = “123”
    }
    }

    静态属性也和方法一样子类不能调用,但是可以继承到

  • class的实例属性可以直接写入到类的定义中去
    
      {
          class myClass {
              name = "kjh";
    
              sayName(){
                  console.log(this.name);
              }
          }
          
          let p = new myClass();
          p.sayName();
          //kjh
      }
    
  • 参考文献 <ES6标准入门>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值