javascript进阶知识19 - class类

143 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情

我们之前创造对象都是使用构造函数,需要使用继承还得使用原型链,稍显繁琐,所以ES6+以后就出了Class类。

class是什么

js里面的class类不是和面向对象语言中(java)的类一样,js里面的class其实是对于原型对象运用的“语法糖”。

class的本质其实是函数:

class Father {}
console.log(typeof Father)  // function

我们打印一下这个类:

image.png

我们发现,他的属性和函数一模一样,都有namelengthargumentsprototype等。

此外:我们可以通过prototype里面的constructor属性来看class和function的区别。

class User {}
// 对比这User构造函数是否等于他的prorotype里面的constructor
console.log(User === User.prototype.constructor); // true

那么class和函数有什么区别呢?

  • 区别1:

    • class声明的类不会发生变量提升,而function声明的函数会发生变量提升。所以我们必须先声明class类,再去使用class类。
  • 区别2:

    • class声明的类不可以重复定义,如果重复定义会报错,而function构造函数的变量名可以被重复定义。

image.png

  • 区别3:

    • 类必须使用 new 调用,否则会报错。这是它跟普通构造函数的一个主要区别,就是后者不用 new 也可以执行
  • 区别4:

    • class类中定义的方法是放在prototype中的,且不可被遍历,而在function里面声明的方法,是在函数身上的,且可被遍历。
  • 区别5:

    • 默认情况下,类定义的代码都在严格模式下进行
  • 区别6:

    • 函数受函数作用域限制,而类受块级作用域限制。

class的使用

1、class的本质就是构造函数:

class Person {
    constructor(name,age) {
        this.name = name;
        this.age = age;
    }
    sayName() {
        console.log(this.name)
    }
}
let ly = new Person('ly',18);
ly.sayName(); // 'ly'

constructor

constructor 方法是类的默认方法,通过 new 命令生成对象实例时,自动调用该方法(默认返回实例对象 this)。一个类必须有 constructor 方法,如果没有显式定义,一个空的 constructor 方法会被默认添加。一个类只能拥有一个名为 “constructor” 的特殊方法,如果类包含多个 constructor 的方法,则将抛出 一个 SyntaxError 。

实例化

class声明的类必须使用new关键字进行调用:

class Person {
	constructor(x, y) {
    this.x = x
    this.y = y
  }
}
Person()
// TypeError Class constructor Person cannot be invoked without 'new'

在使用new操作符实例化Person的操作等于使用new调用其构造函数。js解释器知道使用new和类意味着应该使用constructor函数进行实例化。

类实例化时,传入的参数会被用于构造函数的参数。如果不需要参数,则类后面的括号也可以省略。

class Person {
    constructor(name){
        console.log(arguments.length)
        this.name = name || null;
    }
}

let p1 = new Person;  // 0
console.log(p1.name)  //null

let p2 = new Person(); // 0
console.log(p2.name)   // null

let p3 = new Person('ly')  //1
console.log(p3.name);      // ly

使用new关键字的操作和在构造函数中的步骤是一样的。

2、class类中的方法不能被遍历

在class类中定义的方法,在实例中不能被遍历。

class user {
  constructor(name) {
    this.name = name;
  }
  age = 10;
  show() {}
}

let ly = new user();

for (const key in ly) {
  console.log(key); // age  name
}

console.log(Object.getOwnPropertyDescriptor(user.prototype, "show")); 
// {
//   configurable: true,
//   enumerable: false,
//   value: ƒ show(),
//   writable: true,
// }

而普通函数:

function User(name) {
    this.name = name;
    let age = 20;
    this.sayName = function() {
        console.log(this.name+age)
    }
}
User.prototype.show = function() {
    console.log('haha!')
}
let ly = new User('ly');
for (const key in ly) {
  console.log(key); // name   sayName    show
}
console.log(Object.getOwnPropertyDescriptor(User.prototype,'show'))
// {writable: true, enumerable: true, configurable: true, value: ƒ}

class类的静态属性

在类中属性前面加上 static 表示声明了静态属性,静态属性在类外面无法使用,只能在类内部使用.

class Person {
    constructor(name) {
        this.name = name;
    }
    static nation = 'china';
    show() {
        console.log(`我是${this.name},我来自${Person.nation}`)
    }
}
let ly = new Person('ly');
ly.show();   // 我是ly,我来自china

// 类的静态属性外界获取不到
console.log(ly.nation); // undefined

class类的静态方法

类中的静态方法声明和静态属性声明方式一样,在方法前添加 static 即为静态方法,通过 “类名.方法名” 的方式调用

// 普通方法声明静态方法的方法
function user() {}
user.show = function() {
  console.log("方法的静态方法");
};
user.prototype.show = function() {
  console.log("构造函数的方法");
};

// 把方法作为对象添加的方法为静态方法
user.show(); //方法的静态方法

let u = new user();
u.show(); //构造函数的方法

// 类声明静态方法
class host {
  show() {
    // 这里面的this指向构造函数的对象
    console.log(this === h); // true
    console.log("构造函数方法");
  }
  static show() {
    // 这里面的this指向类本身
    console.log(this === host); // true
    console.log("静态方法");
  }
}
host.show(); // 静态方法

let h = new host();
h.show(); // 构造函数方法