javascript中面向对象中的创建对象
面向对象语言的一个标志就是类的概念,通过类可以创建任意多个具有相同属性和方法的对象
但是在ES6之前,javascript中没有类的概念,当时JS的面向对象是“非正统”且怪异的
使用构造函数(构造方法)用来创建对象
在函数中使用this关键字来指向将要创建的对象,并且没有return语句
function Box(name, age) {
this.name = name;
this.run = function () {
return this.name + "运行中...";
};
}
Box.prototype.sleep = function () {
return this.name + "睡觉中...";
};
// 通过原型添加方法或属性
var box1 = new Box('Lee');
var box2 = new Box('Jack');
构造函数也是函数,但必须使用new运算符,这是构造函数和普通函数的唯一区别
ES6中的类
在ES6中引入了类的概念作为对象的模板,通过class关键字定义类
在class代码块中,所有的方法不需要写function关键字,直接编写函数定义就可以了,方法与方法不要逗号分隔,加了会报错
一个类中必须有构造函数,如果没有显示编写,则会自动添加一个空的构造函数:constructor(){}
class Box{
constructor(name){
this.name = name;
this.run = function () {
return this.name + "运行中...";
};
}
sleep() {
return this.name + "睡觉中...";
}
}
run方法是Box本身的方法
sleep方法是定义在Box原型上的方法,相当于
Box.prototype.sleep = function () {
return this.name + "睡觉中...";
};
ES6中的类实质上就是一个函数,指向的就是构造方法
class Box{...}
typeof Box; // "function"
Box === Box.prototype.constructor // true
所以ES6的class可以看作只是一个语法糖,其本质还是通过ES5中的构造函数来创建对象,新的写法只是让代码更加清晰、更像面向对象编程的语法而已
对象自身的可枚举的属性和方法是在constructor()构造方法中使用this关键字定义的,其余位置定义的方法都是定义在类的原型上,是不可枚举的
在class代码块中,允许在最顶层直接定义自身可枚举属性而无需写在构造函数中,且不需要this和 let/const/var 关键字
class Box{
name = "qian";
age = 33;
sleep() {
return this.name + "睡觉中...";
}
}
这种写法的好处是所有实例对象自身的属性都定义在类的头部,看上去比较整齐,清晰
取值函数(getter)和存值函数(setter)
在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为
class Box{
name = "qian";
age = 33;
get name() {
return this.name + "is good man";
}
set name(new_val) {
this.name = new_val + "is bad man";
}
}
动态属性名和方法名
使用中括号包含变量名可以动态定义属性名或方法名
let demo = "sleep";
class Box{
name = "qian";
[demo](){
return this.name + " sleeping...";
}
}
let box = new();
console.log(box.sleep())
demo = "run"
console.log(box.run())
当变量demo的值改变时,Box的方法名也会跟着改变
class表达式
与函数一样,类也可以使用表达式的形式定义
const Box = class {...}
静态方法和属性
类相当于实例的原型,所有在类中定义的方法,都会被实例继承
如果在一个方法或属性前加上static关键字,就表示不会被实例继承,而是直接通过类来调用
class Box{
static name = "qian";
static run(){
console.log(this.name + "running...");
}
}
let box = new Box();
box.run(); // 报错,因为实例没有继承该方法
Box.run(); // 正常运行
要注意,静态方法中的this关键字指向的是类本身,而不是实例
私有方法和属性
在属性和方法名前面加上井号(#)前缀表示为私有,仅在当前class代码块中可以访问,其他任何地方都无法访问
class Box{
#name = "qian";
#run(){
console.log(this.#name + "running...");
}
// 获取或修改时同样需要加井号(#)前缀
static #sleep(){}
// 静态方法或属性也可以设置为私有
}
当获取一个不存在的静态属性时会报错,而不是向正常属性时返回undefined
in运算符用来判断私有属性或方法是否存在
in运算符只能用在类的内部
class Box{
#name = "qian";
static run(){
console.log(#name in this);
}
}