面向对象编程,就是将需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法)。这个对象,我们称之为类。
创建一个类
在JavaScript中,类其实就是包含属性和方法的对象。
所以创建一个类,就简化成创建一个对象,并添加属性和方法。
按照编程习惯,一般将这个代表类的变量名的首字母大写。
var Book = {
id: 1,
bookname: "哈利波特",
price: 70
}
我们知道,一般类是抽象的,它代表着一些具有共同特征的东西。而上方的这个例子中,书的id、名称、价格都是具体的,它更像是一个对象实例,显然这不是创建类的好方式。
在JavaScript中,函数也是对象。所以可以使用函数来创建类。
var Book = function (id, bookname, price) {
this.id = id;
this.bookname = bookname;
this.price = price;
}
函数的参数可以用来为新对象创建不同的属性。
添加属性或方法的两种方式
- 实例属性或方法
在函数内部通过对this变量添加属性或者方法来实现对类添加属性或者方法。
通过this定义的属性或者方法是实例对象自身拥有的,所以我们每次通过类创建一个新对象时,this指向的属性和方法都会创建。
- 原型属性或方法
在类的原型上添加属性和方法,原型上的属性和方法是共享的,在创建新对象时,不会再次创建。
继承关系图:
image.png属性与方法封装
面向对象的一个特点就是,对一些属性和方法的隐藏于暴露,比如私有属性、私有方法、公有属性、公有方法、特权方法等。
-
私有变量/方法
由于JavaScript的函数作用域,声明在函数内部的变量以及方法在外界是访问不到的,通过此特性即可创建类的私有变量以及私有方法。 -
公有变量/方法
在函数内部通过this创建的属性和方法,在类创建对象时,每个对象自身都拥有一份并且可以在外部访问到。 -
特权方法
通过this创建的方法,不但可以访问这些对象的公有属性和方法,而且还能访问到类创建的私有属性和方法,由于这些方法权利比较大,所以可以当做特权方法。 -
构造器
在对象创建时通过使用特权方法,可以初始化实例对象的一些属性,因此这些在创建对象时调用的特权方法还可以看作是类的构造器。 -
类静态公有属性/方法
通过new关键字创建新对象时,由于类外面通过点语法添加的属性和方法没有执行到,所以新创建的对象中无法获取他们,但是可以通过类来使用。 -
对象共有属性/方法
类通过prototype创建的属性或者方法,在类实例的对象中是可以访问到的,而通过类无法访问。
var Book = function (id, name, price) {
// 私有属性
var num = 1;
// 私有方法
function checkId () {}
// 公有属性
this.id = id;
this.bookname = name;
this.price = price;
// 公有方法
this.copy = function () {};
// 特权方法
this.getName = function () {};
this.getPrice = function () {};
this.setName = function () {};
this.setPrice = function () {};
// 构造器
this.setName();
this.setPrice();
}
// 类静态公有属性
Book.isChinese = true;
// 类静态公有方法
Book.restTime = function () {
console.log("new Time")
};
Book.prototype = {
// 对象共有属性
isJSBook: false,
// 对象共有方法
display: function () {}
}
闭包实现类的静态私有变量和方法
在类外面通过点语法定义的属性以及方法,是类的静态公有属性和方法。
而通过闭包,可以实现添加类的静态私有变量和方法。
var Book = (function () {
// 静态私有变量
var bookNum = 0;
// 静态私有方法
function checkBook(name) {}
// 创建类
function _book(newId, newName, newPrice) {
// 私有变量
var name, price = 0;
// 私有方法
function checkId (id) {};
// 公有属性
this.id = newId;
// 公有方法
this.showNum = function () {
console.log("静态私有变量:", ++bookNum);
};
this.showPrice = function () {
console.log("私有变量:", ++price);
};
// 特权方法
this.getName = function () {};
this.getPrice = function () {};
this.setName = function () {};
this.setPrice = function () {};
// 构造器
this.setName(name);
this.setPrice(price);
}
// 构建原型
_book.prototype = {
// 对象共有属性
isJSBook: false,
// 对象共有方法
display: function () {}
}
// 返回类
return _book;
})();
测试用例
var book_1 = new Book();
// 间接访问类的静态私有变量
book_1.showNum();
// 间接访问私有变量
book_1.showPrice();
var book_2 = new Book();
// 间接访问类的静态私有变量
book_2.showNum();
// 间接访问私有变量
book_2.showPrice();
结果:
每创建一个对象实例,静态私有变量bookNum加1。
私有变量和静态私有变量的区别:
- 每个对象实例都有一份私有变量;
- 所有对象实例共有一份静态私有变量
创建对象的安全模式
为避免在创建对象时忘记使用new关键字,应该使用安全模式创建对象。
即对this进行检测,判断this当前指向的对象是否是类的实例。
instanceof 运算符用来测试一个对象在其原型链中是否存在构造函数(类)的prototype。
var Book = function (id,name, price) {
// 判断执行过程中this是否是当前这个对象
if (this instanceof Book) {
// 构造函数的具体内容
} else {
return new Book(id, name, price);
}
}
网友评论