zoukankan      html  css  js  c++  java
  • ES6 class -- Class 的方法

    静态方法与静态属性

    不会被类的实例所拥有,只有类自身拥有的属性和方法

    只能通过类来调用、

    static 关键字(静态方法)

    类名.属性名=属性值(静态属性)

    //车类
    class Car{
        //构造函数
        constructor(wheel,color,length,width){//接收参数
            //给属性赋值,this指向当前实例化的结果
            this.wheel=wheel;
            this.color=color;
            this.length=length;
            this.width=width;
            this.speed=0;
        }    
    
        //方法
        speedUp(){
            this.speed+=1;
        }
    
        //静态方法
        static repair(car){
            console.log("我要修车,车是:"+car);
        }
    }
    
    //实例化,类->对象
    let c=new Car(3,"#abcdef",20,40);
    Car.repair("我的兰博基尼");//调用静态方法
    c.repair("我的兰博基尼");//实例上没有静态方法,无法调用

    普通方法与静态方法重名,互不影响

    //车类
    class Car{
        //构造函数
        constructor(wheel,color,length,width){//接收参数
            //给属性赋值,this指向当前实例化的结果
            this.wheel=wheel;
            this.color=color;
            this.length=length;
            this.width=width;
            this.speed=0;
            this.errors=0;
        }    
    
        //方法
        speedUp(){
            this.speed+=1;
        }
    
        //自检
        checker(){
            console.log("我要自检");
            //...
            if(this.errors===0){
                console.log("检测完毕,一切正常");
            }
        }
    
        //静态方法
        static checker(car){
            console.log("我要抽查");
        }
    }
    
    //实例化,类->对象
    let c=new Car(3,"#abcdef",20,40);
    Car.checker();//调用静态方法
    c.checker();//调用普通方法

    //车类
    class Car{
        //构造函数
        constructor(){//接收参数
            Car.totolCar++;//操作静态属性,用来计算被实例化的次数
            //给属性赋值,this指向当前实例化的结果
            this.speed=0;
            this.errors=0;
        }    
    
        //方法
        speedUp(){
            this.speed+=1;
        }
    
        //自检
        checker(){
            console.log("我要自检");
            //...
            if(this.errors===0){
                console.log("检测完毕,一切正常");
            }
        }
    
        //静态方法
        static checker(car){
            console.log("我要抽查");
        }
    }
    
    //静态属性
    Car.totolCar=0;
    
    //实例化,类->对象
    let c=new Car();
    console.log(Car.totolCar);//访问静态属性
    new Car();
    new Car();
    new Car();
    Car.checker();//调用静态方法
    c.checker();//调用普通方法
    console.log(Car.totolCar);//再次访问静态属性

    静态属性可以用来储存默认配置

    静态属性和静态方法的具体应用场景

    //角色类
    class Character{
        //构造函数接收参数,实例化时默认会执行
        constructor(pro){
            this.pro=pro;//职业
        }
    }
    
    //配置项(静态属性)
    Character.config={
        //职业映射表
        profession:{
            "咒术师":1,
            "弓箭手":2
        }
    }
    
    let c=new Character(Character.config.profession["咒术师"]);

    class Person{
        //静态方法
        //程序员转普通人
        static format(programmer){
            programmer.bf=true;
            programmer.hair=true;
        }
    }
    
    //程序员类
    class Programmer{
        constructor(){
            this.bf=false;//没有男朋友
            this.hair=false;//没有头发
        }
    }
    
    let p=new Programmer();
    console.log(p);
    Person.format(p);//调用静态方法
    console.log(p);

    类表达式

    //函数表达式
    const a=function(){
    
    }
    
    //函数声明
    function a2(){
    
    }
    
    //类的声明
    class Myclass{
    
    }
    
    //类表达式
    const Myclass2=class{
        constructor(){
            console.log("我是鸽手,咕咕咕");
        }
    }
    
    //也可以class后面跟个类名
    const Myclass3=class M{
        constructor(){
            console.log(M===Myclass3);//内部可以访问到
            //作用:如果Myclass3修改了类名,内部的代码不需要修改,因为用的是内部的类名
            M.a=1;
            console.log("我是鸽手,咕咕咕");
        }
    }
    //console.log("外部:"+M);//报错,外部无法访问到
    
    new Myclass3();

    自执行的类(实际情况基本用不到)

    //自执行的类
    const Person=new class P{
        constructor(){
            console.log(P);
        }
    }();

    getter 与 setter

    类似于给属性提供钩子,在获取和设置属性时做一些额外的事情

    首先看看ES5中getter和setter,一般有两种方式

    1、在对象字面量中书写get/set方法

    const obj={
        name:"",
        get name(){
            return this.name;
        },
        set name(val){
            this.name=val;
        }    
    }
    obj.name;

    这种写法会造成栈内存溢出,因此get name()调用后,return name再次触发get name() ,无线循环

    因此需要修改代码,使get name()和name不同名

    const obj={
        _name:"",
        get name(){
            return this._name;
        },
        set name(val){
            this._name=val;
        }    
    }
    obj.name=222;//调用set name(val)
    console.log(obj);
    console.log(obj.name);//调用get name()

    2、Object.defineProperty

    var obj={
        _name:""
    }
    Object.defineProperty(obj,"age",{
        value:18
    })
    console.log(obj);
    
    //遍历属性时发现age属性无法被遍历
    for(var i in obj){
        console.log(i);
    }

     遍历属性时发现age没有被遍历,这是因为定义属性时没有添加可被枚举的描述符

    添加之后即可被遍历

    var obj={
        _name:""
    }
    Object.defineProperty(obj,"age",{
        value:18,
        enumerable:true//可被枚举
    })
    console.log(obj);
    
    //遍历属性时发现age属性无法被遍历
    for(var i in obj){
        console.log(i);
    }

    可以利用此特性为name书写get和set方法

    var obj={
        _name:""
    }
    Object.defineProperty(obj,"name",{
        get:function(){
            return this._name;
        },
        set:function(val){
            this._name=val;
        }
    })
    
    obj.name=10;
    console.log(obj.name);

    ES6中使用getter和setter

    //ES6中getter和setter
    class Person{
        constructor(){
            this._name=""
        }
    
        get name(){
            return `我的名字是: ${ this._name }`
        }
    
        set name(val){
            this._name=val
        }
    }
    
    const p=new Person();
    p.name="cyy";//调用setter
    console.log(p.name);//调用getter

    模拟一个小案例:

    //ES6中getter和setter的应用
    class AudioPlayer{
        constructor(){
            // 0-暂停 | 1-播放 | 2-加载中
            this._status=0
            this.status=0 //使用setter,默认是0
            this.init()
        }
    
        init(){
            const audio=new Audio()
            audio.src="url"
            audio.canplay=()=>{//如果不使用箭头函数,则this会指向audio;使用后指向当前对象
                audio.play()
                //使用setter
                this.status=1
            }
        }
    
        get status(){
            return this._status
        }
    
        set status(val){
            const STATUS_MAP={
                0:"暂停",
                1:"播放",
                2:"加载中"
            }
            document.querySelector("#app .play-btn").innerText=STATUS_MAP[val]
            this._status=val
        }
    }
    
    const a=new AudioPlayer();

    输入出生年份并自动计算当前年龄的效果

    //定义一个类,设置默认的年龄为18
    class Age{
        constructor(){
            this._age=18;
        }
    
        get age(){
            return this._age;
        }
    
        set age(year){
            //若是设置的年份不是四位数,则采用默认的年龄18
            if(year.length!==4) return;
            this._age=2020-parseInt(year)+1;
        }
    }
    
    //使用变量接收输入的年份
    let year=prompt("请输入出生年份")
    //如果获取到填写的数据
    if (year!=null && year!="")
    {
        let a=new Age();
        a.age=year
        document.write("今年的年龄是:"+a.age);
    }

    name属性与new.target属性

    //name 返回类名
    //不常用
    class Age{}
    
    console.log(Age.name)
    
    //类的表达式
    const Age2=class{}
    console.log(Age2.name)
    
    //类的表达式(存在内部类名),则返回内部类名
    const Age3=class A{}
    console.log(Age3.name)

    //new.target 指向new关键字后面的类
    //不能直接访问,必须在类或者类的构造函数中才能访问
    
    //console.log(new.target)//报错
    
    class Car{
        constructor(){
            console.log(new.target)
        }
    }
    new Car()

    new.target 作用
    语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语

    指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。

    通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

    //语法糖:ES5中模拟类的另一种写法(即下面这种代码的语法糖)
    function Car(){
        //属性
        this...
    }
    //方法
    Car.prototype.xxx=function(){
    
    }

    普通的函数也可以使用new.target

    function fn(){
        console.log(new.target)
    }
    fn()//返回new关键字后面的,如果没有就是undefined
    new fn()

    function Fn(){
        if(new.target!==Fn){
            throw("必须使用new关键字调用")
        }
    }
    Fn()//返回new关键字后面的,如果没有就是undefined
    new Fn()

    也可以使用instanceof实现相同效果

    function Fn(){
        if(!(this instanceof Fn)){
            throw("必须使用new关键字调用")
        }
    }
    Fn()//返回new关键字后面的,如果没有就是undefined
    new Fn()

    let Fnn=class Fn{
        constructor(){
            this.name="cyy"
        }
    }
    let f=new Fnn()
    console.log(f.name)//18
    console.log(Fnn.name)//Fn

    在ES5中模拟类

     其实js是不支持类的,只是用构造函数模拟类

    //ES5中构造函数跟函数一样
    //只是调用时添加了new关键字,就会被当做构造函数
    //如果没有返回值,就会返回对象
    function Person(name,age){
        this.name=name;
        this.age=age;
    }
    console.log(new Person("cyy",18));

    用new关键字为什么会返回对象

    //用new关键字为什么会返回对象
    //1、创建一个空对象
    //2、把构造函数的prototype属性作为空对象的原型
    //3、把this赋值为这个空对象
    //4、执行函数
    //5、如果没有返回值,就返回this
    function Person(name,age){
        this.name=name;
        this.age=age;
    }
    console.log(new Person("cyy",18));

    自己写一个函数模拟构造函数的效果

    function Constructor(fn,args){
        //1、创建一个空对象
        //2、把构造函数的prototype属性作为空对象的原型
        var _this=Object.create(fn.prototype);
        //3、把this赋值为这个空对象
        //4、执行函数
        var res=fn.apply(_this,args);
        //5、如果没有返回值,就返回this
        return res?res:_this;
    }
    
    
    function Person(name,age){
        this.name=name;
        this.age=age;
    }
    Person.prototype.say=function(){
        console.log("我叫"+this.name+",我今年"+this.age+"岁");
    }
    //把函数变为构造函数
    var person=Constructor(Person,["cyy",18]);
    console.log(person);//返回一个对象

  • 相关阅读:
    WPF Step By Step -基础知识介绍
    WPF Step By Step 系列
    设计模式的六大原则
    Java实现二维码生成的方法
    Java 导出Excel
    解析图书 XML
    Maven搭建Spring+SpringMVC+Mybatis+Shiro项目详解
    springboot配置文件的所有属性
    SpringBoot中 application.yml /application.properties常用配置介绍
    Linux 系统目录结构
  • 原文地址:https://www.cnblogs.com/chenyingying0/p/12582189.html
Copyright © 2011-2022 走看看