持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
我们之前创造对象都是使用构造函数,需要使用继承还得使用原型链,稍显繁琐,所以ES6+以后就出了Class类。
class是什么
js里面的class类不是和面向对象语言中(java)的类一样,js里面的class其实是对于原型对象运用的“语法糖”。
class的本质其实是函数:
class Father {}
console.log(typeof Father) // function
我们打印一下这个类:
我们发现,他的属性和函数一模一样,都有name、length、arguments、prototype等。
此外:我们可以通过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构造函数的变量名可以被重复定义。
-
区别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(); // 构造函数方法