js中的class类概念

104 阅读4分钟

1.类声明:类声明不会提升,必须声明后访问,强制访问则抛出错误 referenceError

{
    try {
        let p = new Rectangle() // 报错 referenceError
    } catch({message}) {
    }
    class Rectangle {
        constructor(width, height) {
            this.width = width
            this.height = height
        }
    }
}

2.类表达式:

  •  类表达式可以命名或不命名,命名类表达式的名称是该类体的局部名称,
    
  •  可以通过类的(而不是一个实例的)name属性来访问它
    
    {
        {
            // 不命名
            let Rectangle = class {
                constructor(width, height) {
                    this.width = width
                    this.height = height
                }
            }
            // console.log(Rectangle.name) // Rectangle
        }

        {
            // 命名
            let Rectangle = class Rectangle2 {
                constructor(width, height) {
                    this.width = width
                    this.height = height
                }
            }
            // console.log(Rectangle.name) // Rectangle2
        }
    }
  • 严格模式
  •  类声明和类表达式的主体都执行在严格模式下
    
  •  比如:构造函数,静态方法,原型方法,gettersetter都在严格模式下执行
    
  • 构造函数
  •  1.constructor方法是一个特殊的方法,该方法用于创建和初始化一个由class创建的对象
    
  •  2.一个类只能有一个constructor方法,如果类包含多个constructor方法,则抛出错误 syntaxError
    
  •  3.一个构造函数可以使用super关键字来调用一个父类的构造函数
    
  • 用原型和静态方法绑定this
  •  当调用静态或原型方法时没有指定this的值,那么方法内的this值将被置为undefined。即使你未
    
  •  设置'user strict',因为class体内部的代码总是在严格模式下执行。
    

{
    let Rectangle = class {
        constructor(w, h) {
            try {
                a = 2 // a is not defined
            } catch({message}) {
            }
            this.w = w
            this.h = h
        }

        static private_awidth = 100
        static private_height = 200
        // 私有面积数据
        static area() {
            return this.private_awidth * this.private_height
        }
        
        // 对外提供查询
        area() {
            try {
                a = 2 // a is not defined
            } catch({message}) {
                // console.log(message)
            }
            return this.w * this.h + 'm²'
        }
        
        get area() {
            return this.w * this.h
        }

        get girth() {
            return (this.w + this.h) / 2
        }

        
    }
    let p = new Rectangle(10, 10)
    // console.log(Rectangle.area())
    // console.log(p)
    // console.log(p.area) // 面积
    // console.log(p.girth) // 周长
}

{
    class Subject {
        chinese () {
            return this
        }

        static math() {
            return this
        }
    }
    let s = new Subject()
    // console.log(s.chinese()) // Subject {}
    let c = s.chinese
    // console.log(c()) // undefined
    // console.log(Subject.math()) // class Subject
    let m = Subject.math
    // console.log(m()) // undefined
}
  • 如果上述代码通过传统的基于函数的语法来实现,那么依据初始的this值,在非严格
  • 模式下方法调用会发生自动装箱。若初始值是undefined,this值会被设为全局对象。
{
    function Person() {

    }
    Person.prototype.say = function() {
        return this
    }
    Person.eat = function() {
        return this
    }

    let p = new Person()
    let p1 = p.say
    let p2 = Person.eat
    // console.log(p1()) // global object
    // console.log(p2()) // global object
}
  • 实例的属性必须定义在类的方法里
  • 静态的或原型的数据属性必须定义在类定义的外面
{  
    class Person {
        constructor(name, age) {
            this.name = name
            this.age = age
        }
    }
    Person.sex = '男'
    Person.prototype.adress = '深圳市'
    let p = new Person('张三')
    // console.log(p)
}
  • 公有字段声明
  •  公有类字段
    
  •      公有静态字段和公有实例字段都是可编辑、可枚举和可配置的属性。因此,不同于私有对应值
    
  •      的是,它们参与原型的继承
    
{
    {
        class Rectangle {
            width = 10
            height = 20
        }
        let r = new Rectangle()
        // console.log(r.width, r.height) // 10, 20
    }

    {
        class Rectangle {
            static width = 10
            static height = 20
        }
        let r = new Rectangle()
        // console.log(r) // 无法访问r.width和r.height
    }

    {
        class Rectangle {
            publicMethod() {
                return 'hello world'
            }
        }

    }
}
  • 公有静态字段

{

{
    class Rectangle {
        static width = 10
        static height = 20
        static area // 没有设定初始化的字段将默认被初始化为undefined
    }
    // console.log(Rectangle.width, Rectangle.height, Rectangle.area) // 10 20 undefined
    let r = new Rectangle()
    // console.log(r)
}
{
    class Rectangle {}
    // Rectangle.width = 10
    // Rectangle.height = 20
    Object.defineProperty(Rectangle, 'width', {
        value: 10
    })
    Object.defineProperty(Rectangle, 'height', {
        value: 20
    })
    // console.log(Rectangle.width, Rectangle.height) // 10 20
    let r = new Rectangle()
    // console.log(r.width, r.height)
}

{
    class Rectangle {
        static width
    }
    // console.log(Object.hasOwn(Rectangle, 'width')) // true
    // console.log(Object.hasOwn(Rectangle, 'height')) // false
    // console.log(Rectangle.width) // undefined
}

{
    /**
     * 公有实例字段:
     *      公有实例字段存在于类的每一个实例中;
     *      公有实例字段可以在基类的构造过程中(构造函数主体运行前)使用Object.defineProperty添加
     *      也可以在子类构造函数中的super函数结束后添加
     */
    class Rectangle {
        width = 10
        constructor () {
            this.width = 20
        }
    }

    class Cuboid extends Rectangle{
        constructor() {
            super()
        }
    }


    let r = new Rectangle()
    let c = new Cuboid()
    // console.log(r)
    // console.log(c)
}

{
    class Rectangle {
        width = 10
        constructor () {
            this.width = 20
        }
        output() {
            return this.width
        }
    }

    let r = new Rectangle()
    // console.log(r.output()) // 20
}

{
    class Rectangle {
        constructor() {
            console.log('r', this.width) // undefined
        }
    }

    class Cuboid extends Rectangle {
        width = 10
        constructor() {
            super()
            console.log('c', this.width) // 10
        }
    }
    // let c = new Cuboid()
}

{
    /**
     * 因为类字段是通过Object.defineProperty()添加的,
     * 所以派生类中的字段声明并不会调用基类中的setter,此行为不同于在构造函数中使用this.file = ''
     */
    
    {
        class Rectangle {
            set file (val) {
                console.log(val)
            }
        }

        class Cuboid extends Rectangle {
            file = 10
        }

        let c = new Cuboid() // no log
        // console.log(c)
    }

    {
        class Rectangle {
            set width(val) {
                console.log(val)
            }
        }
        class Cuboid extends Rectangle {
            constructor() {
                super()
                this.width = 10
            }
        }
        // let c = new Cuboid() // log 10
    }
}

/**
 * 公有静态方法
 *      关键字static 将为一个类定义一个静态方法,静态方法不是在一个实例上被调用
 *      而是在类自身之上被调用。 它们通常是工具函数,比如用来创建和复制对象
 */

{
    class MyArray extends Array {
       
    }
    let arr = new MyArray(1, 2, 3, 4)
    let arr2 = new Array(1, 2, 3, 4)

    // console.log(arr)
    // console.log(arr2)
}

/**
 * 使用super调用超类
 *      super关键字用于调用对象的父对象上的函数
 */
{
    class Cat {
        constructor(name) {
            this.name = name
        }

        speak() {
            console.log(this.name + 'makes a noise')
        }
    }

    class Lion extends Cat {
        speak() {
            super.speak()
            console.log(this.name + 'roars.')
        }
    }
}

}