面向对象编程——封装
javascript有两种编程风格:面向过程和面向对象
所谓的面向对象就是将你的需求抽象成一个对象然后针对这个对象分析其属性和方法,这个对象我们称之为类,他的一个特点就是封装。
封装
-
创建一个类
var Book = function(id, bookname, price){ this.id = id; this.bookname = bookname; this.price = price; } var book = new Book(10, 'javascript模式设计', 50); console.log(book.bookname);
通过this添加的属性和方法同在prototype中添加的属性和方法的区别:通过this添加的属性和方法是在当前对象上添加的,然而javascript是基于prototype上的语言是,所以没创建一个对象时,他都有一个原型prototype用于指向其继承的属性和方法。这样,通过prototype继承的方法并不是对象自身,所以在使用这些方法时,需要通过prototype一级一级的查找的到。因此,通过this定义的属性或方法是对象自身拥有的,所以我们每次通过类创建一个新对象时,this指向的属性和方法都会得到相应的创建,而通过prototype继承的属性和方法是每个对象通过prototype访问到的,所以不在创建。
-
属性和方法的封装
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.setName(name); } //类静态共有属性(对象不能访问) Book.isChinese = true; //类静态共有方法(对象不能访问) Book.resetTime = function(){ console.log('new tiem') }; Book.prototype = { //共有 isJSBook: false, display: function(){} } var b = new Book(11, 'javascript模式设计', 50); console.log(b.num);//undefined console.log(b.isJSBook);//false console.log(b.id);//11 console.log(b.isChinese);//undefined console.log(Book.isChinese);//true Book.resetTime();//new tiem
由于javascript的函数级作用域,声明在函数内部的变量和方法在外界是访问不到的,通过此特性,可创建类的私有变量和方法。然而在函数内部通过this创建的属性和方法,在类创建对象时,每个对象都拥有一份并且可以在外部访问到。因此通过this创建的属性可以看作共有属性和方法。
通过new关键词创建的对象实质上是对新对象this的不断赋值。
-
闭包实现类的静态变量
var Book = (function(){ //静态私有变量 var booknum = 0; //方法 function checkBook(name){ } //返回构造函数 return function(newId, newName, newPrice){ //私有变量 var name,price; //方法 function checkId(id){} //特权方法 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(name); this.setName(price); } })(); Book.prototype = { //共有 isJSBook: false, display: function(){} }; var b = new Book(11, 'javascript模式设计', 50); console.log(b.num); console.log(b.isJSBook); console.log(b.id);
闭包是有权限访问另一个函数作用域中变量的函数,即在一个函数内部创建另一个函数。我们将这个闭包作为创建对象的构造函数,这样它即是闭包又可实例对象的函数,可以访问到类函数作用域中的变量。
-
创建对象的安全模式
对于初学者来说,经常容易忘记使用new而犯错误。如:var Book = function(title, time, type){ this.title = title; this.time = time; this.type = type; } var book = Book('javascript模式设计', '2014', 'js'); console.log(book);//undefined console.log(window.title);//javascript模式设计
new关键词的作用可以看成是对当前对象的this不停的赋值,但是这里没有new,所以就会直接执行这个函数,而这个函数在全局作用域中执行了,所以在全局作用域中this就是全局变量,在页面里面全局变量就是window。
为了避免这样的错误,我们就可以给他设计一个安全模式:
var Book = function(title, time, type){
//判断执行过程中this是否是当前对象
if(this instanceof Book){
this.title = title;
this.time = time;
this.type = type;
}else{
return new Book(title, time, type);
}
}
var book = Book('javascript模式设计', '2014', 'js');
console.log(book);//Book
console.log(window.title);//undefined
这样就不用再担心忘记new关键词的问题了。