zoukankan      html  css  js  c++  java
  • ES6中的class的详解

    JavaScript输入弱类型的语言,在JS中并没有像Java中的那样的类的概念,以后可能也不会有,ES6中的class实际上也是基于JavaScript中的一个强大的属性,也就是原型属性prototype,由这个属性改良得来的一种语法糖。

    JS是基于原型的面向对象语言。原型对象特点就是将自身的属性共享给新对象。这样的写法相对于其它传统面向对象语言来讲,很有一种独树一帜的感脚!虽然强大,但也非常容易让人困惑!

    第一部分:那么ES6中的class是怎么工作的呢?

    在ES6之前,如果要生成一个对象,那么需要先定义一个构造函数,再使用new操作符来成长这个构造函数的实例对象。

    下面是一个构造函数的例子

    function Person(name, age) {
        this.name = name;
        this.age=age;
    }
    
    Person.prototype.say = function(){
        return "我的名字叫" + this.name+"今年"+this.age+"岁了";
    }
    
    var obj=new Person("李大师",30);
    
    //通过构造函数创建对象,必须使new 运算符
    
    console.log(obj.say());//我的名字叫李大师今年30岁了

    第二部分:构造函数生成实例对象的过程是这样的:

    1.当使用了构造函数,并且new 构造函数(),后台会隐式执行new Object()创建对象;
    2.将构造函数的作用域赋给新对象(即new Object()创建出的对象),而函数体内的this就代表new Object()出来的对象。
    3.执行构造函数的代码。
    4.返回新对象(后台直接返回);

    ES6中的class写法就很简洁了
    class Person{ //定义了一个名字为Person的类
        constructor(name, age){//constructor是一个构造方法,用来接收参数
            this.name = name;//this代表的是实例对象
            this.age=age;
        }
        say(){//这是一个类的方法,注意千万不要加上function
            return "我的名字叫" + this.name+"今年"+this.age+"岁了";
        }
    }
    var obj=new Person("李大师", 30);
    console.log(obj.say());//我的名字叫李大师今年30岁了

    第三部分: 那么 class到底是个什么东西呢? 

    console.log(typeof Person); //function
    console.log(Person === Person.prototype.constructor); //true

    从这两段代码可以看书,其实Person类实质上就是一个函数。类自身指向的就是构造函数。所以可以认为ES6中的类其实就是构造函数的另外一种写法.

    类的所有方法都定义在类的prototype属性上面

    Person.prototype.addFn=function(){
        return "我是通过prototype新增加的方法,名字叫addFn";
    }
    var obj=new Person("李大师",30);
    console.log(obj.addFn());
    //我是通过prototype新增加的方法,名字叫addFn

    除此之外,我们还可以通过Object.assign方法来为对象动态的增加方法,

    Object.assign(Person.prototype, {
       getName : function() {
          return this.name
      },
      getAge : function() {
         return this.age
      }
    })
    
    var obj=new Person("李大师",30);
    console.log(obj.getName());//李大师
    console.log(obj.getAge());//30

    第四部分: constructor

    constructor 方法时类的构造函数的默认方法,通过new 命令生成实例对象时,自动调用该方法

    class Box{
        constructor(){
            console.log("啦啦啦,今天天气好晴朗");//当实例化对象时该行代码会执行。
        }
    }
    var obj=new Box();
    
    // 啦啦啦,今天天气好晴朗

    constructor方法如果没有显式定义,会隐式生成一个constructor方法。所以即使你没有添加构造函数,构造函数也是存在的。constructor方法默认返回实例对象this,但是也可以指定constructor方法返回一个全新的对象,让返回的实例对象不是该类的实例。

    class Desk{
        constructor(){
            this.xixi="我是一只小小小小鸟!哦";
            return this
        }
    }
    class Box{
        constructor(){
           return new Desk();// 这里没有用this哦,直接返回一个全新的对象
        }
    }
    var obj=new Box();
    console.log(obj.xixi);//我是一只小小小小鸟!哦

    constructor 中定义的属性或方法与 constructorz外定义的属性或方法有什么区别呢?

    class Person {
        constructor() {
            this.name = '李大师';
            this.age = 30;
            this.showName = function() {
                 console.log(this.name)
            }
            this.showweight = function(){
                console.log(this.weight)
           }
        }
    
        height = 175;
    
        weight=70;

    sex = 'man';

    salary= 500000; showAge() { console.log(
    this.age) } showheight(){ console.log(this.height) }

    showSex = function(){
    console.log(this.sex)
    }

    showSalary = ()=>{
    console.log(this.salary)
    } } const person
    = new Person(); console.log(person.hasOwnProperty('name')); // true console.log(person.hasOwnProperty('name')); // true console.log(person.hasOwnProperty('height')); // true console.log(person.hasOwnProperty('weight')); // true console.log(person.hasOwnProperty('showName')); // true console.log(person.hasOwnProperty('showAge')); // false console.log(person.hasOwnProperty('showheight')); // false console.log(person.hasOwnProperty('showweight')); // true
    console.log(person.hasOwnProperty('showSex'));
    // true
    console.log(person.hasOwnProperty('showSalary'));
    // true

    从上面的代码我们可以看出

    (1)无论是在constructor中,通过this.name = name 这种方式所绑定的属性和方法,最终会在实例对象中体现出来

    (2)在constructor外部,通过showSex = function(){} 或者 showSalary = ()=>{} 这种方式绑定的方法,也会在实例对象中体现出来,有图为证

    (3)在constructor外部,通过showAge(){}  这种方式绑定的方法,实际上是将方法绑定在了Person.prototype上面,有图为证

    那么可以解释一个现象

    Person.prototype.showAge()

    // undefined
    // 这个方法实际上输出的是undefined,因为Person.prototype上面并没有age这个属性

    一句话来总结:class中,所有的属性,无论是否在contructor中指定,都会绑定到class的实例对象上;class中,通过showAge(){}这种方式绑定的方法,会默认的绑定到class的prototype属性上面去,并不会在class的实例对象上体现,而通过constructor中的this.showName = function(){}  或者constructor外部的 showSex = function(){} 这样的形式绑定的方法,将会绑定到class的实例对象上面去,在prototype上面并不会有体现。

    根据上面的原则,我们可以发现,如果要定义一个class,那么对于那些需要在后代中继承的方法,可以通过showAge(){} 这样的形式,绑定到class的prototype属性上去,如果不需要在后代中继承,只需要在实例中使用的方法,就可以通过在constructor中定义,或者通过showSex = ()=>{} 这样的方式,绑定到它的实例对象中区。

    第五部分:继承

    在ES6中,使用extends关键字来实现继承

    class Animal  {
        constructor(){}
    
        name = 'animal';
        age = 3;
    
        showName() {
          console.log( 'animalName =' + this.name)
        }
    
        showAge = ()=>{
          console.log('animalAge = ' + this.age)
       }
    }
    
    class Dog extends Animal {
        constructor(){
         super()
       }
        name='dog';
        age=5;
        fullname = 'Dog';
        sex='male';
       
        showSex() {
          console.log(this.sex)
        }
    
        showName =()=> {
         console.log('name' + this.name)
       }
    
        showFullName(){
          console.log(this.name + this.fullname)
        }
    }
    
    const dog = new Dog();
    
    dog.showAge();
    
    //animalAge = 5 
    
    dog.showName();
    // namedog
    
    dog.showSex();
    // male
    
    delete dog.showName
    
    dog.showName()
    
    // animalName =dog

    我们可以发现,如果一个class的方法并不是定义在prototype方法上,而是像通过赋值一样showName = ()=>{} 这种方式,那么如果delete 了 实例对象上的属性,这个属性就会消失,再执行这个方法,就会向上访问它的原型 dog.__proto__ 也就是Dog.prototype上去查找,但是Dog.prototype上面也是没有showName属性的,那么它只好向上查找,因为Dog是Animal的子类,Dog.prototype.__proto__ === Animal.prototype, Animal.prototype上面是有showName属性的,那么可以得到最后一个结论,delete dog.showName之后 ,dog.showName()  会输出 animaleName =dog

         

     
  • 相关阅读:
    201671010116. 2016-2017-10《Java程序设计》第10周学习总结
    201671010116. 2016-2017-8《Java程序设计》第9周学习总结
    201671010116. 2016-2017-8《Java程序设计》第8周学习总结
    Java学习计划
    201671010114 2016-2017-2 《Java程序设计》学习总结
    2016-2017-2 《Java程序设计》第十六周学习总结
    201671010114 2016-2017-2 《Java程序设计》第十五周学习总结
    201671010114 2016-2017-2 《Java程序设计》第十四周学习总结
    201671010114 2016-2017-2 《Java程序设计》第十三周学习总结
    201671010114 2016-2017-2 《Java程序设计》第十二周学习总结
  • 原文地址:https://www.cnblogs.com/liquanjiang/p/11705868.html
Copyright © 2011-2022 走看看