8. 函数
函数是用对象来实现的(早期js中没有class概念,会用一个函数当做类;js有了ES6以后,ES6中定义好了class,一般就用class了。)
// 定义方式1 其中function是修饰符 add的类型是function js中函数名可以任意赋值
function add(a, b) {
return a + b;
}
let add = function (a, b) {
return a + b;
}
// 定义方式2(简写方法,可以不写function)
let add = (a, b) => {
return a + b;
}
let main = function() {
console.log(add(3, 4) // 这里的3, 4是参数,定义add函数的时候写了a, b两个参数,此处书写两个或两个以上参数都是可以正常执行的(多传的参数没有意义只执行有意义的部分),如果只定义一个参数或者一个参数都不定义则会得到undefined结果。
}
返回值
如果未定义返回值,则返回undefined。
9. 类
与C++中的Class类似。但是不存在私有成员,全部都是公开的。
类可以理解为前端的每一个组件,每一个组件还可以进行细分,每个细分的组件都是又一个新的class。
this指向类的实例
class Point { // 定义一个类名为point
constructor(x, y) { // 构造函数名称固定(constructor) 该构造函数有两个参数(x, y)
this.x = x; // 成员变量 定义类的成员变量(使用this. class中的this表示当前对象中的当前实例(实例就是第20行的参数,一个类可以生成多个实例),类似Python中的self)名称为x
this.y = y;
this.init();
}
init() { // 定义一个成员函数 (此处不需要书写function)
this.sum = this.x + this.y; // 成员变量可以在任意的成员函数中定义
}
toString() { // 成员函数
return '(' + this.x + ', ' + this.y + ')';
// 14行的格式化写法如下
// return `(${this.x}, ${this.y})`;
}
}
let p = new Point(3, 4); // 定义一个对象
console.log(p.toString());
类名一般使用驼峰命名法(每个单词首字母大写)
继承
class ColorPoint extends Point { // 表示ColorPoint继承自Point
constructor(x, y, color) {
super(x, y); // 这里的super表示父类的构造函数 这里的super(指代父类的构造函数)就是Point中的constructor(改行必须书写且应该书写至第一行)
this.color = color; // 这一行的this.属性需要在super之后调用,否则会报错
}
toString() {
return `this.color + ' ' + super.toString()`; // 调用父类的toString() 该行中的super不同与第3行的super,第3行的super只能用于构造函数中。本行的super指的是子类这个对象(除了在第三行的位置是指代父类的构造函数以外,均为该含义),此处super类似于this,表示指向当前实例的父类的实例(this指向当前对象的实例)
}
}
注意:
- super这个关键字,既可以当作函数使用,也可以当作对象使用。
作为函数调用时,代表父类的构造函数,且只能用在子类的构造函数之中。
super作为对象时,指向父类的原型对象。
- 在子类的构造函数中,只有调用super之后,才可以使用this关键字。(与js的底层实现有关)
- 成员重名时,
子类的成员会覆盖父类的成员。类似于C++中的多态(同一个函数表现出来多个状态的功能)。
静态方法
在成员函数前添加static关键字即可。静态方法不会被类的实例继承,只能通过类来调用。例如:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
static print_class_name() {
console.log("Point"); // 打印当前类名
}
}
let p = new Point(1, 2); // 初始化一个实例
Point.print_class_name(); // 正确访问方法,通过类名(此处为Point)识别
p.print_class_name(); // 会报错 因为没有把 print_class_name()继承过来
静态变量
静态变量:变量是与类绑定的并不是与实例绑定的(普通的变量是和每一个实例绑定的)
可以尽量少的避免重名变量的发生
在ES6中,只能通过class.propname定义和访问。例如:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
Point.cnt++; // 每调用一次函数,就让静态变量进行++运算
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
Point.cnt = 0; // 定义了一个Point的静态变量
let p = new Point(1, 2);
let q = new Point(3, 4);
console.log(Point.cnt);
静态函数可以理解为所有实例公共的函数;
静态变量可以理解为所有实例共有的变量;
静态变量可以理解为全局变量。
静态函数用得少,静态变量会用得到。
静态成员函数是可以被继承的