类
类是用于创建对象的模板。Javascript中生成对象实例的方法是通过构造函数,这跟主流面向对象语言(java,C#)写法上差异较大,如下:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 1);
ES6 提供了更接近Java语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
如下:constructor()是构造方法,而this代表实例对象:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
类的数据类型就是函数,它本身就是指向函数的构造函数:
// ES5 函数声明
function Point() {
//...
}
// ES6 类声明
class Point {
//....
constructor() {
}
}
typeof Point // "function"
Point === Point.prototype.constructor // true
在类里面定义的方法是挂到Point.prototype,所以类只是提供了语法糖,本质还是原型链调用。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
Point.prototype = {
//....
toString()
}
var p = new Point(1, 1);
p.toString() // (1,1)
类的另一种定义方式类表达式
// 未命名/匿名类
let Point = class {
constructor(x, y) {
this.x = x;
this.y = y;
}
};
Point.name // Point
函数声明和类声明有个重要区别,函数声明会提升,类声明不会提升。
let p = new Point(); // 被提升不会报错
function Point() {}
let p = new Point(); // 报错,ReferenceError
class Point {}
constructor()
constructor()方法是类的默认方法,new生成实例对象时会自动调用该方法。
一个类必须有constructor()方法,如果没有显式定义,引擎会默认添加一个空的constructor()。
constructor()方法默认返回实例对象(即this)。
class Point {
}
// 自动添加
class Point {
constructor() {}
}
getter和setter
与 ES5 一样,在类的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。
class User {
constructor(name) {
this.name = name;
}
get name() {
return this.name;
}
set name(value) {
this.name = value;
}
}
this
类的方法内部的this,它默认指向类的实例,在调用存在this的方法时,需要使用 obj.method()方式,否则会报错。
class User {
constructor(name) {
this.name = name;
}
printName(){
console.log('Name is ' + this.name)
}
}
const user = new User('jack')
user.printName() // Name is jack
const { printName } = user;
printName() // 报错 Cannot read properties of undefined (reading 'name')
如果要单独调用又不报错,一种方法可以在构造方法里调用bind(this)。
class User {
constructor(name) {
this.name = name;
this.printName = this.printName.bind(this);
}
printName(){
console.log('Name is ' + this.name)
}
}
const user = new User('jack')
const { printName } = user;
printName() // Name is jack
bind(this) 会创建一个新函数,并将传入的this作为该函数在调用时上下文指向。
另外可以使用箭头函数,因为箭头函数内部的this总是指向定义时所在的对象。
class User {
constructor(name) {
this.name = name;
}
printName = () => {
console.log('Name is ' + this.name)
}
}
const user = new User('jack')
const { printName } = user;
printName() // Name is jack
静态属性
静态属性指的是类本身的属性,而不是定义在实例对象this上的属性。
class User {
}
User.prop = 1;
User.prop // 1
静态方法
可以在类里面定义静态方法,该方法不会被对象实例继承,而是直接通过类来调用。
静态方法里使用this是指向类。
class Utils {
static printInfo() {
this.info();
}
static info() {
console.log('hello');
}
}
Utils.printInfo() // hello
关于方法的调用范围限制,比如:私有公有,ES6暂时没有提供,一般是通过约定,比如:在方法前面加下划线_print()表示私有方法。
如果你想开发小程序或者了解更多小程序的内容,可以通过专业开发公司,来帮助你实现开发需求:厦门在乎科技-专注厦门小程序定制开发、APP开发、网站开发、H5小游戏开发
继承
Java中通过extends实现类的继承。ES6中类也可以通过extends实现继承。
继承时,子类必须在constructor方法中调用super方法,否则新建实例时会报错。
class Point3D extends Point {
constructor(x, y, z) {
super(x, y); // 调用父类的constructor(x, y)
this.z = z;
}
toString() {
return super.toString() + ' ' + this.z ; // 调用父类的toString()
}
}
父类的静态方法,也会被子类继承。
class Parent {
static info() {
console.log('hello world');
}
}
class Child extends Parent {
}
Child.info() // hello world
super关键字
在子类的构造函数必须执行一次super函数,它代表了父类的构造函数。
class Parent {}
class Child extends Parent {
constructor() {
super();
}
}
在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。
class Parent {
constructor() {
this.x = 1;
this.y = 10
}
printParent() {
console.log(this.y);
}
print() {
console.log(this.x);
}
}
class Child extends Parent {
constructor() {
super();
this.x = 2;
}
m() {
super.print();
}
}
let c = new Child();
c.printParent() // 10
c.m() // 2
_proto_和prototype
初学Javascript时,_proto_和prototype 很容易混淆。首先我们知道每个JS对象都会对应一个原型对象,并从原型对象继承属性和方法。
- prototype 一些内置对象和函数的属性,它是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。
- _proto_ 每个对象都有这个属性,一般指向对应的构造函数的prototype属性。



