介绍封装之前我们先简单介绍一下面向对象:
在javascript设计模式一书中是这样介绍的,面向对象编程就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)和动作(方法)。这个对象我们称之为类。
那么我们今天来介绍面向对象编程的第一个特点——封装。
封装就是把你需要的功能放在一个对象里。
可以这样简单的理解:比如你搬家,有很多需要那的东西,你将他们统统装在行李箱内一起打包搬走,这样不论是携带还是管理都会更加方便。
我们首先来创建一个Book类,创建类很容易,首先我们声明一个函数存在一个变量中,然后在这个函数(类)的内部通过对this(函数内部自带的一个变量,用来指向当前对象)变量添加属性或者方法来实现对类添加属性和方法,例如:
var Book=function(id,bookname,price){
this.id=id;
this.bookname=bookname;
this.price=price;
}
也可以在类的原型上添加属性和方法(类也是对象,所以有原型prototype),一种是意义为原型对象添加属性,一种则是将一个对象赋值给类的原型对象,两种方法不要混合使用
//为书籍添加展示方法
Book.prototype.display=function(){}
//或者
Book.prototype={
display:function(){}
}
我们使用的时候就可以直接使用new关键字创建(实例化)一个Book对象
var book=new Book(2,'javascript设计模式',30);
console.log(book.bookname)//javascript设计模式
那么我们接下来看一下通过this创建的属性和方法与通过prototype创建的属性和方法有什么区别:
通过this关键字创建的属性和方法是在当前对象上添加的,然而js是一种基于原型prototype的语言,所以每创建一个对象时,它都会有一个原型prototype用于指向其继承的属性和方法。这样通过prototype继承的方法并不是自身的,所以使用这些方法的时候需要通过prototype一级一级查找得来。这样就不难理解每次通过类创建一个新的对象时,this指向的属性和方法都会的到相应的创建,而通过prototype继承的属性和方法是每个对象通过prototype来访问的,所以这是通过类新创建的对象的属性和方法不会被再次创建。
如下图:
我们再看一下上图中的constructor,它是一个属性,当创建一个对象的时候就会为其创建一个原型对象prototype,在prototype对象中又会像函数中创建this一样创建一个constructor属性,那么constructor属性指向的就是拥有整个原型对象的函数或对象。例如Book prototype中的constructor属性指向book对象。
接下来我们看一下封装:
由于javascript是函数级作用于,在函数内部声明的变量和方法在外界访问不到,通过此特性就可以创建类的私有变量和私有方法。然而在函数内部通过this关键字创建的属性和方法,在类创建对象的时候每个对象都会拥有一份并且可以被外部访问,因此通过this创建的属性和方法我们可称之为共有属性和共有方法,然而通过this创建的方法,不但可以访问这些对象的共有属性和共有方法,还可以访问类创建时声明的私有变量和私有方法,由于这些方法权利比较大,所以我们又可称之为特权方法。
通过特权方法的特点我们可以在对象创建的时候通过特权方法初始化实力对象的一些属性,因此这些在创建对象时调用的特权方法有被称为类的构造器
接下来我们看一下例子:
var Book=function(id,name,price){
//私有属性
var num=1;
//私有方法
function checkId(){};
//特权方法
this.getName=function(){};
this.getPrice=function(){};
this.setName=function(){};
this.setPrice=function(){};
//对象公有属性
this.id=id;
//对象公有方法
this.copy=function(){};
//构造器
this.setName(name);
this.setPrice(price);
}
关于类的实例访问类的属性和方法还要注意以下情况:
在类外面通过点语法添加的属性和方法,由于在通过new创建对象的时候没有执行到点语法添加的属性和方法,所以通过对象无法访问到这些属性和方法,这些属性和方法被成为类的静态共有属性和类的静态共有方法。
而通过prototype创建的属性或者方法,在类实例对象的时候可以通过this访问到,所以我们将通过prototype创建的属性和方法称为共有属性和共有方法。举个🌰:
//静态共有属性(不可以通过对象访问,通过类来访问)
Book.isChinese=true;
//静态共有属性(不可以通过对象访问,通过类来访问)
Book.resetTime=function(){
console.log(new Date());
}
Book.prototype={
//共有属性
isJsBook:true,
//共有方法
display:function(){}
}
var b=new Book(11,'javascript设计模式',30);
console.log(b.num);//undefined
console.log(b.isJsBook);//true
console.log(b.id);//11
consoel.log(b.isChinese);//undefined
console.log(Book.isChinese);//true
Book.resetTime();//当前时间
由于通过new创建的对象实质是对新对象this的不断赋值,并将prototype指向类的prototype所指向的对象,而类的构造函数外面通过点语法定义的属性和方法不会添加的新创建的对象上,才会有以上结果。
接下来我们看一下闭包的实现:
有时候我们经常将类的静态变量通过闭包来实现
闭包是有权访问另外一个函数作用域中变量的函数,即在一个函数内部创建另一个函数。我们将这个闭包作为创建对象的构造函数,这样它既是闭包优势可实例对象的函数,即可以访问到函数作用域中的变量。举个🌰:
//利用闭包实现
var Book=(function(){
//静态私有变量
var bookNum=0;
//静态私有方法
function checkBook(name){};
//创建类
function book(newId,newName,newPrice){
//私有变量
var name,price;
//私有方法
function checkId(newId){};
//特权方法
this.getName=function(){};
this.getPrice=function(){};
this.setName=function(){};
this.setPrice=function(){};
//公有属性
this.id=newId;
//公有方法
this.copy=function(){};
bookNum++;
if(bookNum>100){
throw new Error('只能出版100本书');
}
this.setName(newName);
this.setPrice(newPrice);
}
book.prototype={
//静态公有属性
isJsBook:true,
//静态公有方法
display:function(){}
}
return book;
})
我们在写代码的过程中有时候可能会丢失关键字new导致调用结果错误。这是我们可以使用创建对象的安全模式。
如一下代码:
//图书类
var Book=function(title,time,type){
this.title=title;
this.time=time;
this.type=type;
}
//错误实例化(丢失关键字new)
var book=Book('javascript','2018','js');
console.log(book);//undefined
//为什么会出现这种结果呢,我们先看一下测试代码
console.log(window.title);//javascript
console.log(window.time);//2018
console.log(window.type);//js
好奇怪!这是什么原因呢?
例子中在没有用关键字new的时候,这是只是单纯的调用了Book函数而已,而这个函数是在全局作用域下面执行的,所以会将属性挂在到window对象上去。
这是我们就可以通过安全模式来避免这个错误。直接上代码:
var Book=function(title,time,type){
//判断执行过程中this是否是当前的对象(如果是说明是通过new创建的)
if(this instanceof Book){
this.title=title;
this.time=time;
this.type=type;
}else{
//重新创建对象
return new Book(title,time,type);
}
}
var book=Book('javascript','2018','js');
console.log(book.title);//javascript
console.log(window.title);//undefined
这就是创建类的安全模式
让每一次分享都变的更有意义