javscript中的OOP特性
1 引言
js也是具有OOP(object oriented programming)特性的,OOP在构建一些大型应用程序还是有一套成熟理论的。作为C++的使用者在学习js中的OOP特性的过程中,能够较快地理解其中的各种术语和概念,也能比较两种语言的异同,深化知识理解。通过js的OOP特性的学习也让我开始从语言层面考虑程序设计问题。
本篇文章主要介绍了js中的一些OOP特性,并且比较了js与C++的语言特性。如果你能熟练掌握C++的OOP特性,本文能帮助你快速地对js中的OOP特性建立整体的认识。
2 写给C++使用者的js中的OOP特性介绍
2.1 创建对象(object)
js中创建object的代码,示例如下:
let duck = {
name: "Aflac",
numLegs: 2,
sayName: function() {
return "The name of this duck is " + this.name + ".";
}
};
js直接通过 {}
就可以创建出对象示例来,不需要对该对象(object)的类(class)进行声明。这点和C++不是很相同,C++需要先声明一个class再创建object。
这个object有两个成员变量和一个成员函数,需要注意的是这两个成员变量都是公有(public)的,他们是可以直接用 .
符号访问的。
js中也有 this
关键字,与C++相同, this
关键字用于表示当前实例。
2.2 类(class)的声明
js中声明一个类的操作实际上就是声明一个构造函数。
let Bird = function(name, color) {
this.name = name;
this.color = color;
this.numLegs = 2;
}
let crow = new Bird("Alexis", "black");
crow instanceof Bird; // => true
上面的代码声明了Bird类,在js中通常类的名字都是由首字母大写的单词表示的。类的构造函数也能接受参数用于对实例的初始化,这点与C++非常相似,使用 new
关键字就能够创建该类的实例。
使用 instanceof
关键字用于检查对象是否属于某个类,也可通过验证 constructor
属性来判断一个对象是否属于一个类 crow.constructor == Bird
。
2.3 类的共有成员
js中通过 prototype
这一属性(把它叫做关键字好像还不太合适)能够实现C++中静态成员变量和静态成员函数的特性。
Bird.prototype.numLegs = 2;
上面的代码就给Bird类增加了一个静态成员变量。这个 prototype
可以是一个对象,这样类的共有成员就能方便地承载更多的属性了,示例代码如下。
Bird.prototype = {
constructor: Bird,
numLegs: 2,
eat: function() {
console.log("nom nom nom");
},
describe: function() {
console.log("My name is " + this.name);
}
};
需要注意的是需要设置好 constructor
属性,这样是为了保证代码逻辑的一致性。
对象会获得类的 prototype
属性,可以通过 isPrototypeof
方法来验证。
Bird.prototype.isPrototypeOf(duck);
2.4 类的私有成员
js与C++一样,也可以有私有成员变量,代码如下所示。 hatchedEgg
就相当与是Bird的私有成员变量,并且提供了修改这个成员变量的方法 getHatchedEggCount
。
function Bird() {
let hatchedEgg = 10; // private property
this.getHatchedEggCount = function() {
// publicly available method that a bird object can use
return hatchedEgg;
};
}
let ducky = new Bird();
ducky.getHatchedEggCount(); // returns 10
这种形式在js中被称作闭包(closure),函数能够访问到与他处在同一个作用域(context)中的变量。
2.5 类的继承和派生
js中的派生主要通过 prototype
体现,下面的代码表示Bird派生自Object。同样,需要注意将 constructor
属性设置好。
Bird.prototype = Object.create(Animal.prototype);
Bird.prototype.constructor = Bird;
2.6 类的覆盖
js中可以重写基类中的方法,代码如下所示,这点与C++中的 override
相同。
function Animal() { }
Animal.prototype.eat = function() {
return "nom nom nom";
};
function Bird() { }
// Inherit all methods from Animal
Bird.prototype = Object.create(Animal.prototype);
// Bird.eat() overrides Animal.eat()
Bird.prototype.eat = function() {
return "peck peck peck";
};
Bird.prototype.fly = function() {
console.log("I'm flying!");
};
通样也在派生之后也可以通过修改派生类的 prototype
以达到特化派生类的作用,上面的 fly
方法就是在Bird完成派生之后新增的方法。现在Bird有两个方法,它们分别是 eat
和 fly
。