知识点:

[简介](#1-简介)[^1]
[严格模式]()
[constructor方法]()
[类的实例对象]()
[Class表达式]()
[不存在变量提升]()
[ES6 class 中的 私有方法 ](#7-私有方法-es6-class不提供私有方法,只能模拟实现)
[ES6 class 中的私有属性](#8-私有属性-es6通过表示私有属性)
ES6 class [this指向](#9-类方法中this的指向)
[ES6 class name属性](#10-name属性返回class关键字后面的类名)

1 简介

7 私有方法 es6 class不提供私有方法,只能模拟实现

// es6不提供私有方法,必须通过变通方法实现
        // 实现方式1
        class Dog {
            // 公有方法
            sayName(name) {
                this_bar(name)
            }
            // 私有方法
            _bar(baz) {
                return this.snaf = baz
            }
        }
        // 实现方式2
        class Car {
            // 公有方法
            showPrice(length) {
                carLength.call(this, length)
            }
        }
        // 私有方法2
        function carLength(length) {
            return this.snaf = length
        }

        // 实现方法3
        const cbar = Symbol('bar')
        const csnaf = Symbol('snaf')

        export default class myClass {
            // 公有方法
            foo(baz) {
                this[cbar](baz)
            }
            // 私有方法
            [cbar](baz) {
                return this[csnaf] = baz
            }
        }

ES5 私有方法:在构造函数中通过var let const 定义的属性-- 私有方法本身是可以访问类内部的所有属性的,即私有属性和公有属性。但是私有方法是不可以在类的外部被调用

ES5 公有方法:在构造函数的prototype定义的方法,可以被外部调用,但是不能访问私有属性和方法

ES5 特权方法:可以访问私有属性和私有方法的公有方法

私有方法:

在某些情景下,你可能希望限制某些属性和方法的暴露程度,使他们不能通过对象实例本身被访问、修改或调用。许多传统语言可以将属性和方法定义为公有、私有或者受保护的。私有变量或方法在类定义之外不能被进行读写;受保护的变量不能被直接访问;但可以通过一个包装方法对其读写。在js中并没有具体的语法来定义私有或受保护的变量和方法,不过我们可以对声明“类”的方法做一些改变,从而限制对属性和变量的访问。

特权方法:

在构造函数中通过var let const定义的变量其作用域局限于该构造函数内——在prototype上定义的方法无法访问这个变量,因为这些方法有其自己的作用域。想要通过公有的方法来访问私有的变量,需要创建一个包含两个作用域的新作用域。为此,我们可以创建一个自我执行的函数,称为闭包。代码如下。

// JavaScript有一个非强制的但很有用的编程惯例,
// 就是对所以私有变量或函数名加一个下划线(_)作为前缀,以标识他们是私有的。

        const  Alarm = (function() {
            function Alarm() {}

            // 私有属性
            let _isLocked = false
            let _isAlarmed = false
            let _alarmMsg = '闹钟正在响'

            // 私有方法
            function _alarm() {
                _isAlarmed = true
                alert(_alarmMsg)
            }
            function _disableAlarm() {
                _isAlarmed = false
            }
            // **所有定义在原型上方法都是“公有”的,当我们在此处创建的类在闭包结束处被返回后,就可以在当前作用域之外**
            // 访问这些方法了
            Alarm.prototype.lock = function() {
                _isLocked = true
                _alarm()
            }
            Alarm.prototype.unlock = function() {
                _isLocked = false
                _disableAlarm()
            }
            // 定义一个getter函数来对来对私有变量的值作只读访问——相当于受保护的
            Alarm.prototype.getIsLocked = function () {
                // 只返回,没提供修改的方法即是只读的
                return _isLocked
            }
            // setter函数进行只写访问
            Alarm.prototype.setAlarmMsg = function(msg) {
                _alarmMsg = msg
            }

            return Alarm
        }())

        const house = new Alarm()
        house.lock() // => 弹出 '闹钟正在响'
        // house._alarm() // => 报错 实例对象不能访问私有属性和方法

        console.log( house.getIsLocked() ) // => true (返回isLocked,但不允许对其直接访问,所以该变量是只读的)
        house.setAlarmMsg('闹钟正在叮叮叮')
        house.lock() // => 弹出 '闹钟正在叮叮叮'

        // 一般情况下,我们应该讲所有变量和函数都定义为私有,除非明确需要将某些变量和方法公开暴露给外部。
        // 即使需要公开暴露,也应先考虑使用getter和setter方法来访问变量,这么做的好处是可以限制他人所能实施的操作,
        // 使其只能通过“类”提供的功能完成其需求,这样有助于减少“类”的使用者代码出错的机会

        // 例子2
        function Student() {
            // 私有
            let _id = 9527
            let _name = '唐伯虎'
            function _show() {
                window.alert(`_show ${_id} ${_name}`)
            }
            // 公有
            this.age = 20
            this.show = function() {
                _show()
            }
        }
        const student = new Student()
        alert(`${student._id} ${student._name} ${student.age}`) // => undefined undefined 20
        student.show() // => _show 9527 唐伯虎

8 私有属性 es6通过#表示私有属性


9 类方法中this的指向


10 name属性返回class关键字后面的类名


11 Class的取整函数(getter)和存值函数(setter)

// 类中通过 get set 设置取值函数和存值函数
        class Cat {
            get prop() {
                console.log( 'getter-取值')
            }
            set prop(value) {
                console.log( 'setter:'+ value )
            }
        }
        const myCat = new Cat()
        myCat.prop = 123
        myCat.prop

get set实际设置在 属性的描述对象上面,和es5相似


12 Class的Generator方法(某方法前加 *表示该方法为Generator函数)


13 Class的静态方法(构造函数的方法)

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。(构造函数自有的方法,例如A.sayName()

// Class中的静态方法
        class Points {
            static classMethod() {
                return '这是静态方法'
            }
        }
        // 子类可以继承父类的静态方法
        class Son1 extends Points {}

        console.log(Son1.classMethod()) // => '这是静态方法'

        // 静态方法也可以从super对象上调用
        class Son2 extends Points {
            static sonClassMethod() {
                return super.classMethod() + '通过super继承父方法'
            }
        }
        console.log(Son2.sonClassMethod()) // => '这是静态方法通过super继承父方法'

14 Class的静态属性和实例属性

es6 规定 Class内部只有静态方法,没有静态属性,因此只有下面写法正确

class Dog {
        }
        Dog.leg = 4
        console.log(Dog.leg) // => 4

        // 下面写法都不对
        // class Cat {
        //     leg: 4
        //     static sy: '喵喵'
        // }

静态属性的提案

1 类的实例属性

// 类的实例属性可以用等式,写入类的定义之中
        class Dog {
            // myProp = 42;

            constructor() {
                return this.myProp // 42
            }
        }
        let hsq = new Dog()
        console.log(hsq) // Dog {}

        // 之前的写法 constructor方法里面定义
        // class Alsj extends Dog {
        //     constructor() {
        //         super()
        //         this.state = {
        //             count: 1
        //         }
        //     }
        // }
        // const alsj = new Alsj()
        // console.log(alsj.state.count) // => 1

        // 通过=改写 这个写法浏览器目前报错 SyntaxError: Unexpected token =
        // class Alsj extends Dog {
        //     state = {
        //         count: 1
        //     }
        // }
        // const alsj = new Alsj()
        // console.log(alsj.state.count)

        // 为提高可读性,在constructor里面定义的实例属性,新方法可以直接列出
        class Alsj extends Dog {
            // state // => 目前浏览器SyntaxError: Unexpected identifier
            constructor() {
                super()
                this.state = {
                    count: 1
                }
            }
        }
        const alsj = new Alsj()
        console.log(alsj.state.count)

2 类的静态属性

// 类的静态属性老方法
        class Dog {}
        Dog.leg = 4

        // 新写法
        class Cat {
            static leg = 4 // 直接写浏览器报错
        }
        const cat = new Cat()
        console.log(cat.leg)

15 new.target属性

es6引入new.target属性,返回new命令作用于的那个构造函数,不是通过new调用的返回undefined

// 使用方式1
        function Person(name) {
            if ( new.target !== undefined ) {
                this.name = name
            } else {
                throw new Error('实例化必须通过new生成')
            }
        }
        const person1 = new Person('Jeson')
        // const person2 = Person('Tom')
        console.log(person1) // => Person {name: "Jeson"}
        // console.log(person2) // => Uncaught Error: 实例化必须通过new生成

        // 使用方式2
        function People(name) {
            if ( new.target === People) {
                this.name = name
            } else {
                throw new Error('实例化必须通过new生成')
            }
        }
        const people1 = new People('Jack')
        // const people2 = People('sam')
        console.log(people1) // => Person {name: "Jeson"}
        // console.log(people2) // => Uncaught Error: 实例化必须通过new生成

new.target返回当前的类,利用这个特点可以写出不能独立使用,必须继承后才能使用的类

// 父类
        class Animale {
            constructor() {
                if ( new.target === Animale ) {
                    throw new Error('父类不能实例化')
                }
            }
        }
        class Dog extends Animale {
            constructor(name) {
                super();
            }
        }
        // const x = new Animale('狗') // 报错
        const y = new Dog('狗')
1. 返回

results matching ""

    No results matching ""