• JS类—class


    典型的面向对象编程语言(比如C++和Java)存在类(class)这个概念。所谓类就是对象的模板,对象是类的实例

    JS中没有类,在ES5中使用构造函数(constructor)作为对象的模板。但是ES5中实现继承的代码非常冗长与混乱(盗用构造函数、组合继承、原型式继承等等),因此在ES6中新引入了class关键字具有了正式定义类的能力

      类(class)是ECMAScript中新的基础性语法糖结构。其背后使用的仍然是原型和构造函数的概念

    1.类定义

    class Person {}
    const Person = class {}

     说明:

    • class声明不存在变量提升:
      • console.log(classDemo);
        class classDemo {};        // var_let_const.html:12 Uncaught ReferenceError: Cannot access 'classDemo' before initialization
    • 函数受函数作用域限制,而类受块作用域限制:
      •         {
                    class classDemo { };
                }
        
                console.log(classDemo);        // var_let_const.html:16 Uncaught ReferenceError: classDemo is not defined
    • 类名首字母同函数构造函数一样,建议类名首字母大写

    2.类构造函数

    constructor关键字用于在类定义块内部创建类的构造函数。方法名constructor会告诉解释器在使用new操作符创建类的新实例时,应该调用这个函数。

    构造函数非必须,不定义相当于构造函数为空

    示例:

            class Person { 
                constructor(override){
                    console.log("我是一个人")
                }
            };
    
            let p1 = new Person()        // 我是一个人

     (1)使用new实例化类

      使用new实例化的操作等于使用new调用其构造函数,new执行的操作有:

    • 在内存中创建一个新对象
    • 这个新对象内部的__proto__属性赋值为构造函数的prototype属性
    • 构造函数内部的this被赋值为这个新对象(this指向了新对象)
    • 执行构造函数内部的代码
    • 如果构造函数返回非空对象,则返回该对象,否则返回刚创建的新对象

    说明:

    • 类实例化时传入的参数会用作构造函数的参数。如果不需要参数,则类名后面的括号是可选的
    • 类构造函数与构造函数的主要区别在于:
      • 调用类构造函数必须使用new操作符。不使用new则会抛出错误(Uncaught TypeError: Class constructor Person cannot be invoked without 'new'
      • 而普通构造函数如果不使用new调用,那么就会以全局的this(window)作为内部对象

    (2)把类当成特殊函数

    JS中并没有正式的类这个类型。从各方面看,ECMAScript的类就是一种特殊的函数。可以使用typeof 检测表明它是一个函数:

            class Person { };
    
            console.log(typeof Person);    // function
    • 可以使用instanceof操作符检查一个对象是不是类的实例:
    1         class Person {};
    2 
    3         let p = new Person()
    4 
    5         console.log(p instanceof Person);    // true
    • 类也可以向其他对象或者函数引用一样把类作为参数传递
     1         let pList = [
     2             class Person {
     3                 constructor ( id ){
     4                     this._id = id
     5                     console.log("类作为参数:",this._id)
     6                 }
     7             }
     8         ]
     9 
    10         function createIns( classDefinition, id ){
    11             return new classDefinition(id)
    12         }
    13 
    14         let foo = createIns(pList[0],1234)    // 类作为参数: 1234
    •  类还可以立即实例化
    1         let foo = new class Person {
    2             constructor(id) {
    3                 console.log("立即实例化对象")
    4             }
    5         }

    3.实例、原型和类成员

    每次通过new调用类标识符时,都会执行类构造函数,在这个函数内部,可以为新创建的实例(this)添加自有属性。且构造函数执行完毕以后,仍然可以给实例继续添加新成员。

    (1)实例成员

    每个实例都对应一个唯一的成员对象,即所有成员都不会在原型上共享:

     1         class Person {
     2             constructor(id) {
     3                 this.name = new String('Jack')
     4 
     5                 this.sayName = () => console.log(this.name);
     6 
     7                 this.nickNames = ['张三','李四']
     8             }
     9         }
    10 
    11         let p1 = new Person(),p2 = new Person();
    12 
    13         p1.sayName();    // Jack
    14         p2.sayName();    // Jack
    15         console.log(p1.name === p2.name); // false
    16         console.log(p1.sayName === p2.sayName); // false
    17         console.log(p1.nickNames === p2.nickNames); // false

    (2)原型方法与访问器

    为了在实例间共享方法,类定义语法把在类块中定义的方法作为原型方法

     1         class Person {
     2             constructor() {
     3                 // 存在这个类的不同的实例上
     4                 this.locate = () => console.log("instance");
     5             }
     6             // 在类块中定义的所有内容都会定义在类的原型上
     7             locate() {
     8                 console.log("prototype");
     9             }
    10         }
    11 
    12         let p = new Person()
    13 
    14         p.locate()    // instance
    15         Person.prototype.locate()    // prototype
    • 可以把方法定义在类构造函数中或者类块中,但不能在类块中给原型添加原始值或对象作为成员数据
    1         class Person {
    2             name: '张三'
    3         }
    4         // Uncaught SyntaxError: Unexpected identifier
    • 类方法等同于对象属性,因此可以使用字符串、符号或计算的值作为键
     1         let funName = "fn02"
     2 
     3         class Person {
     4             
     5             fn01(){
     6                 console.log("字符串属性名");
     7             }
     8 
     9             [funName](){
    10                 console.log("变量属性名");
    11             }
    12 
    13             ['fn' + '03'](){
    14                 console.log("计算属性名");
    15             }
    16 
    17         }
    18         
    19         let p = new Person()
    20         p.fn01()    // 字符串属性名
    21         p.fn02()    // 变量属性名
    22         p.fn03()    // 计算属性名
    • 类定义也支持get与set访问器:
     1         class Person {
     2 
     3             set name(newName){
     4                 console.log("设置新值为:",newName);
     5                 this._name = newName
     6             }
     7             
     8             get name(){
     9                 console.log("读取到新值:",this._name);
    10                 return this._name
    11             }
    12 
    13         }
    14         
    15         let p = new Person()
    16         p.name = "张三"        // 设置新值为: 张三
    17         p.name    // 读取到新值: 张三

     (3)非函数原型和类成员

    类定义并不显式支持在原型或类上添加成员数据,但是可以在类定义外部手动添加:

     1         class Person {
     2 
     3             sayName() {
     4                 console.log(`${ Person.greeting }${ this.name }`);
     5             }
     6 
     7         }
     8         // 在类上定义数据成员
     9         Person.greeting = ' 我的名字是'
    10         // 在原型上定义数据成员
    11         Person.prototype.name = '张三'
    12         
    13         let p = new Person()
    14         p.sayName()    // 我的名字是张三
  • 相关阅读:
    (紫书,感谢作者)第7章暴力求解法
    明日更新
    明天更新
    UVa11882最大的数(dfs+剪枝)
    UVa12569树上的机器人的规划
    es6中的reduce方法?
    浏览器是如何渲染页面的?
    判断是不是一个数组?
    判断是否是一个数组?
    var与let的区别?
  • 原文地址:https://www.cnblogs.com/codexlx/p/14287358.html
Copyright © 2020-2023  润新知