zoukankan      html  css  js  c++  java
  • ES6-10笔记(class类)

    class类

    Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。摘自阮一峰老师语录

    class声明

    ES5的JavaScript中只有对象,想要模拟类去生成一个对象实例,只能通过定义一个构造函数,然后通过new操作符来完成。

    let Animal = function (type) {
      this.type = type
    }
    
    Animal.prototype.walk = function () {
      console.log(`I am walking`)
    }
    
    let dog = new Animal('dog')
    let monkey = new Animal('monkey')
    
    //构造函数生成实例的执行过程
    1.当使用了构造函数,并且new 构造函数(),后台会隐式执行new Object()创建对象;
    2.将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this就代表new Object()出来的对象。
    3.执行构造函数的代码。
    4.返回新对象(后台直接返回);
    

    ES6引入了Class(类)这个概念,通过class关键字可以定义一个类

    class Animal {
      constructor (type) {
        this.type = type
      }
      walk () {
        console.log(`I am walking`)
      }
    }
    let dog = new Animal('dog')
    let monkey = new Animal('monkey')
    
    

    但是Class的类型还是function,并且console.log(Animal.prototype);结果几乎是一样的,所以可以认为class声明类的方式是function声明类方式的语法糖。甚至在class声明类后仍可使用ES5的方式来为这个类添加,覆盖方法。

    console.log(typeof Animal); //function
    
    ES5中打印的console.log(Animal.prototype)
    //{eat: ƒ, constructor: ƒ}
    //eat: ƒ ()
    //constructor: ƒ (type)
    //__proto__: Object
    
    ES6中打印的console.log(Animal.prototype)
    //{constructor: ƒ, eat: ƒ}
    //constructor: class Animal
    //eat: ƒ eat()
    //__proto__: Object
    
    除了constructor后边分别是f(type)和class Animal
    

    class不存在变量提升,所以需要先定义再使用。因为ES6不会把类的声明提升到代码头部,但是ES5就不一样,ES5存在变量提升,可以先使用,然后再定义。

    //ES5可以先使用再定义,存在变量提升
    new A();
    function A(){
    
    }
    //ES6不能先使用再定义,不存在变量提升 会报错
    new B();//B is not defined
    class B{
    
    }
    

    Setters&Getters

    类中的属性,可以直接在constructor中通过this直接定义,还可以通过get/set直接在类的顶层定义

    class Animal {
      constructor (type, age) {
        this.type = type
        this._age = age
      }
      get age () {
        return this._age
      }
      set age (val) {
        this._age = val
      }
    }
    

    get可以定义一个只读属性

    class Animal {
      constructor (type) {
        this.type = type
      }
      get addr () {
        return '北京动物园'
      }
    }
    

    get/set可以进行一些简单封装,如下

    class CustomHTMLElement {
      constructor (element) {
        this.element = element
      }
      get html () {
        return this.element.innerHTML
      }
      set html (value) {
        this.element.innerHTML = value
      }
    }
    

    get/set还可以模拟设置私有属性,并可以通过get和set对获取属性和读取属性进行一些逻辑判断

    let _age = 4
    class Animal{
    	constructor(type) {
    	    this.type = type
    	}
    	get age() {
    		if(this.type == 'dog'){
    				return _age
    		}else{
    			return "I don't know"
    		}
    	}
    	set age(val){
    		if(val<7&&val>4){
    			_age = val
    		}
    	}
    	eat () {
    		console.log('i am eat food')
    	}
    }
    
    let dog = new Animal('dog')
    let cat = new Animal('cat')
    console.log(dog.age)//4
    console.log(cat.age)//I don't know  在get age中只有dog能拿到_age
    dog.age = 6
    console.log(dog.age)//6
    dog.age = 8
    console.log(dog.age)//6  在set age中传入参数必须小于7大于4才能生效
    

    继承

    ES5中继承的实现

    // 定义父类
    let Animal = function (type) {
      this.type = type
    }
    // 定义方法
    Animal.prototype.walk = function () {
      console.log(`I am walking`)
    }
    // 定义静态方法
    Animal.eat = function (food) {
      console.log(`I am eating`)
    }
    // 定义子类
    let Dog = function () {
      // 初始化父类
      Animal.call(this, 'dog')
      this.run = function () {
        console.log('I can run')
      }
    }
    // 继承
    Dog.prototype = Animal.prototype
    

    ES6中通过extends关键字实现继承。

    子类必须在constructor方法中调用super方法,之后才能使用this关键字,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象。如果不调用super方法,子类就得不到this对象。在这一点上ES5的继承与ES6正好相反,ES5先创建自己的this对象然后再将父类的属性方法添加到自己的this当中。

    如果子类没有显式的定义constructor,那么下面的代码将被默认添加(不信可以尝试下,哈)。换言之,如果constructor函数中只有super的话,该constructor函数可以省略。

    class Animal {
      constructor (type) {
        this.type = type
      }
      walk () {
        console.log(`I am walking`)
      }
      static eat () {
        console.log(`I am eating`)
      }
    }
    
    class Dog extends Animal {
      constructor () {
        super('dog')
      }
      run () {
        console.log('I can run')
      }
    }
    

    静态方法 static Methods&静态属性

    静态方法是面向对象最常用的功能,在ES5中利用function实现的类是这样实现一个静态方法的

    let Animal = function (type) {
      this.type = type
      this.walk = function () {
        console.log(`I am walking`)
      }
    }
    
    Animal.eat = function (food) {
      console.log(`I am eating`);
    }
    

    在ES6中使用static的比纳基是不是静态方法

    class Animal {
      constructor (type) {
        this.type = type
      }
      walk () {
        console.log(`I am walking`)
      }
      static eat () {
        console.log(`I am eating`)
      }
    }
    

    静态方法不需要实例化可以直接通过类调用

    class Animal{
        static a(){
            return "我是Animal类中的,实例方法,无须实例化,可以直接调用"
        }
    }
    //通过类名直接调用
    console.log(Animal.a());//我是Animal类中的,实例方法,无须实例化,可直接调用!
    

    静态方法只能在静态方法中调用,不能在实例方法中调用

    class Animal{
        static a(){
            return "我只允许被静态方法调用哦!"
        }
        static b(){
            //通过静态方法b来调用静态方法a
            console.log(this.a());
        }
    }
    Animal.b();//输出:我只允许被静态方法调用
    
    
    

    通过实例方法来调用静态方法会报错

    class Animal{
        static a(){
            return "我只允许被静态方法调用哦!"
        }
        b(){
            console.log(this.a());//TypeError: this.a is not a function
        }
    }
    var obj=new Animal();
    obj.b();
    
    //其他地方想要调用静态方法可借助类来调用,如使用Animal.b()
    class Animal{
        static a(){
            return "我只允许被静态方法调用哦!"
        }
        static b(){
            //通过静态方法b来调用静态方法a
            console.log(this.a());
        }
        c(){
        	console.log(Animal.b())
        }
    }
    Animal.b();//输出:我只允许被静态方法调用
    let dog = new Animal()
    Animal.c()////输出:我只允许被静态方法调用
    

    父类的静态方法,可以被子类继承

    class Animal {
        static a() {//父类Animal的静态方法
            return '我是父类的静态方法a';
        }
    }
    class Dog extends Animal {}
    //子类Dog可以直接调用父类的静态方法a
    console.log(Dog.a()); 
    

    想通过子类的静态方法调用父类的静态方法,需要从super对象上调用

    class Animal {
        static a() {
            return '我是通过super来调取出来的';
        }
    }
    class Dog extends Animal {
        static a(){
            return super.a();
        }
    }
    console.log(Dog.a()); //我是通过super来调取出来的
    

    静态属性指的是 Class 本身的属性, 即Class.propname, 而不是定义在实例对象( this) 上的属性。

    class Animal{
       constructor(){
           this.name="实例属性"
       }
    }
    Animal.prop1="静态属性1";
    Animal.prop2="静态属性2";
    console.log(Animal.prop1,Animal.prop2);//静态属性1  静态属性2
    

    类的应用场景

    前端各种框架起飞,基本不需要去使用类来实现或者完善前端页面功能,在服务端写node.js的话可能会经常使用类语法。

    下方代码是用类实现在同一个页面设置多个分页列表。(这个功能多数UI框架也解决了。。。)

    class PageUtil{
    	constructor(pageNo,pageSize,total){    //构造初始变量
    		this.pageNo = pageNo;     //起始页面
    		this.pageSize = pageSize  //一页数据条数
    		this.total = total        //数据总数
    		this.currentPage = 0      //当前选中页数
    		this.pageTotal = Math.ceil(this.total/this.pageSize)   //总页数
    	}
    	nextPage(){     //下一页
    		if(this.currentPage < this.pageTotal){
    			this.currentPage++
    		}
    	}
    	beforePage(){    //上一页
    		if(this.currentPage > 1){
    			this.currentPage--
    		}
    	}
    	jumpPage(page){     //跳页
    		this.currentPage = page
    	}
    	changePageSize(pageSize){    //改变页大小
    		this.pageSize = pageSize
    		this.pageTotal = Math.ceil(this.total/this.pageSize)   //总页数
    	}
    	getTotalPage(){    //获取总页数
    		return Math.ceil(this.total/this.pageSize)
    	}
    }
    
    
    class DialogPage extends PageUtil{    //继承PageUtil类
    	constructor(pageNo,pageSize,total,pageTotal){
    		super(pageNo,pageSize,total)
    		this.pageTotal = pageTotal
    	}
    	getTotalPage(){
    		return this.pageTotal || super.getTotalPage()   //重写getTotalPage方法
    	}
    }
    const contentPage = new PageUtil(1,10,100)   //实例化2个pageUtil对象
    contentPage.getTotalPage()
    console.log(contentPage.currentPage)
    contentPage.nextPage()
    console.log(contentPage.currentPage)
    const dialogPage = new DialogPage(1,10,100,10)
    console.log(dialogPage.currentPage)
    dialogPage.getTotalPage()
    

    实现一个类具有Push,PoP功能

    class Myarray {
           constructor(arr) {
           this.arr = arr;
       }
       myPop() {
           if (this.arr.length === 0) return undefined;
           return Number(this.arr.splice(this.arr.length - 1, 1))
       }
       myPush() {
           let _this = this;
           Array.from(arguments, el => _this.arr.splice(_this.arr.length, 0, el))
           return this.arr.length;
       }
    }
    let arr = Array.of(1, 5, 6, 7, 8)
    let myArray = new Myarray(arr);
    console.log(myArray.myPop(), arr)
    console.log(myArray.myPush(null), arr)
    
  • 相关阅读:
    day-11函数的形参与实参
    day-10初级函数
    .检查用户名是否使用接口
    04.vue发送短信逻辑
    03.celery发送短信接口
    02.celery配置与基本使用
    Celery介绍
    python爬虫与Django框架vue交互的前后端代码详情(励志人生网实例)
    爬虫找工作之面试题(2)
    爬虫找工作之面试题(1)
  • 原文地址:https://www.cnblogs.com/xingchenhuanqi/p/12906099.html
Copyright © 2011-2022 走看看