类和对象
类
JS 中是支持类的,可以使用 class
关键字来新建一个类:
class MyClass {
// ...
}
通常我们约定类名为大写开头,之后每个单词首字母大写。
然后来看看类的内容。
this
this
关键字表示一个类对象本身,如果在类内需要使用自身的一些函数什么的,就可以通过 this 来调用。
构造函数
类可以拥有自己的构造函数,这个函数的名字只能是 constructor
,可以自定义参数。
class MyClass {
constructor() {
// ···
}
}
构造函数的作用就是在创建一个类时执行的动作。
静态成员
静态成员表示整个类的所有对象都共享的值,可以使用关键字 static
在类内定义,也可以使用[类名].成员定义。
比如这样:
class MyClass {
static inner = 1;
}
MyClass.outer = 2;
这两种方法的效果是一样的,但通常推荐第一种。
函数
类中可以定义函数,这时可以省略关键字 function
:
class MyClass {
// 普通函数
func() {
console.log('function');
}
// 静态函数
static funcStatic() {
console.log('static function');
}
}
类字段
在类中想声明一个字段的话,可以在类中的任意地方声明,并且在其他地方使用(当然声明还是要在使用之前,如果在声明之前就调用的话,会是一个undefined)。
使用 this.[字段名]
就可以声明一个类字段了。通常,我们会在构造函数里定义一写需要在这个类里使用的字段。当然在其他地方定义也是可以的。
class MyClass {
// 在类中定义 name 字段
constructor() {
this.name = 'myclass';
}
// 第一次调用的时候,this.something是个undefined,所以就进入else
// else 里会定义this.something
sayName() {
if (this.something) {
console.log(this.something);
}
else {
this.something = 123;
console.log(this.name);
}
}
}
get 和 set 访问器
如果想设置一个只读或者只写的字段,就可以使用这个特性。只要在一个函数前,加上 get
或者 set
就好了。
class MyClass {
get give() {
return 5;
}
get value() {
return this.someFiledWithALooooooooooooooogName;
}
set value(newValue) {
this.someFiledWithALooooooooooooooogName = newValue;
}
}
使用的时候依旧可以像一个普通变量一样使用他们。
let obj = new MyClass();
console.log(obj.five); // 5
obj.value = 123;
console.log(obj.value); // 5
继承类们
类也是可以继承的,使用 extend
关键字就好。在子类的构造函数里,使用 super
函数就可以调用父类的构造函数。
class MyClass {
constructor(init) {
this.value = init;
}
}
class NewClass extend MyClass {
constructor(initValue, elseInitValue) {
super(initValue);
this.init = elseInitValue;
}
}
对象(Object)
类定义了怎么组织数据,然后在使用的时候需要使用关键字 new
来声明一个该类的实例,这个实例就是一个类对象。
创建指定类的对象
let obj = new MyClass();
来一个匿名类的对象
有的时候,我们会需要组织一些数据,但只用在一个地方,这时候再写类的话就会比较麻烦。所以我们可以直接用一个花括号来创建一个对象。
let obj = {
name: 'obj',
value: 'lalala',
sayHello: function(name) {
console.log('Hello, ' + name);
},
sayHi: (name) => {
console.log('Hi! ' + name);
}
};
在花括号内写的是一个个的“键-值”对(Key-Value Pair),之后就可以和普通对象一样使用了。在定义函数时,可以使用关键字 function ,也可以使用箭头函数,两个的效果一样。
需要注意的是,在每一个键-值对直接需要用逗号分隔。
对象是浅复制的
浅复制的意思就是很浅的复制(呸)。
好吧其实就是说,看上去像复制了,但实际上只是给之前的变量创建了一个别名,来看个栗子就好理解了。
let obj1 = { name: 'obj' };
let obj2 = obj1;
obj2.name = 'new name';
console.log(obj2.name); // 'new name'
console.log(obj1.name); // 'new name'
但如果你将拷贝后的对象完全改成另一个对象,原先的对象是不会跟着改变的。
let obj1 = { name: 'obj' }
let obj2 = obj1;
let obj3 = obj1;
obj2 = 123;
console.log(obj1); // { name: 'obj' }
obj1 = 456;
console.log(obj3); // { name: 'obj' }
如果想深度拷贝的话,需要用到下一节的方法。
一个看上去很厉害的词:解构
这一节的内容暂时无法在 node 中使用
JS 提供了一种语法,能够很方便的获取一个对象中的部分字段,这种语法叫做解构。
let obj = { name: 'obj', age: 12, isAlive: true };
let { name, age } = obj;
console.log(name); // 'obj'
console.log(age); // 12
这样,就不用在每次调用前加个 obj.
了。
解构还有一种语法,可以将整个对象展开,这样就能对一个对象进行深度拷贝了。用法很简单,就是在一个对象前加 ...
符号就好。
let obj = { name: 'obj', age: 12, isAlive: true };
let newObj = { ...obj };
obj.name = '???';
console.log(newObj.name); // 'obj'
其实对象是个字典(Dictionary)
什么是字典呢,就是有一个键,通过键可以查到对应的值。
对象里的字段名就是一个键,这个键的类型是一个字符串;字段的值就是一个键对应的值,所以你可以通过将键作为下标,来获取一个字段的值。
let obj = { name: 'obj' };
console.log(obj['name']); // 'obj'
这和用 .
调用没什么区别。
然后 JS 提供了一种叫 for...in
的方式,可以遍历一个对象内的所有字段。
let obj = { name: 'obj', age: 12, isAlive: true };
for (o in obj) {
console.log(o + ': ' + obj[o]);
}
// 输出 'obj', 12, true