灵活的语言-JavaScript
用对象收编变量
function checkName() {
//验证姓名
};
function checkEmail() {
//验证邮箱
};
function checkPassword() {
//验证密码
};
这是一个验证表单功能的代码,但存在问题就是这就创建了三个全局变量,当团队协作的时候,就很容易覆盖掉原有的变量,此时咱们就可以用对象收编变量:
var CheckObject = {
checkName: function() {
},
checkEmail: function() {
},
checkPassword: function() {
}
};
对象的其他定义形式
var CheckObject = function() {};
CheckObject.checkName = function() {
},
CheckObject.checkEmail = function() {
},
CheckObject.checkPassword = function() {
};
这样写也是可以创建对象,且通过CheckObject.checkName()能够使用,但是当别人需要使用时候无法是无法复制或者通过new关键字使用这些方法的。
如果只是单纯的想复制一下可以这样写:
var CheckObject = function() {
return {
checkName: function() {
},
checkEmail: function() {
},
checkPassword: function() {
}
}
};
var a = CheckObject();
a.checkName();
这样每个人使用执行都是一个新对象,不会互相影响,但是这还不是真正意义上的类,既然这样我们就来创建一个真正意义的类:
var CheckObject = function() {
this.checkName = function() {
},
this.checkEmail = function() {
},
this.checkPassword = function() {
}
};
var a = new CheckObject();
a.checkName();
此时当多个实例化对象时候都会有属于自己的一套方法,不会相互影响了。但是在创建新的对象的时候会对类的this的每个属性进行复制,但是有时候是会造成很大的消耗的,所以需要处理一下:
var CheckObject = function() {};
CheckObject.prototype.checkName = function() {
},
CheckObject.prototype.checkEmail = function() {
},
CheckObject.prototype.checkPassword = function() {
};
var a = new CheckObject();
a.checkName();
这样创建实例的时候就不会一个个去复制了,而是都是依赖prototype原型寻找,当然,这种方法重复写prototype很麻烦我们也可以这样写:
var CheckObject = function() {};
CheckObject.prototype = {
checkName: function() {
},
checkEmail: function() {
},
checkPassword: function() {
}
};
var a = new CheckObject();
a.checkName();
a.checkEmail();
a.checkPassword();
通过以上代码发现调用了三个方法,但是对象a重复书写了三遍,所以此时我们可以改进一下:
var CheckObject = function() {};
CheckObject.prototype = {
checkName: function() {
return this;
},
checkEmail: function() {
return this;
},
checkPassword: function() {
return this;
}
};
var a = new CheckObject();
a.checkName().checkEmail().checkPassword;
此时我们就可以链式调用了。
JavaScript是一种灵活的语言,函数在其中扮演着一等公民,所以使用JavaScript可以编写出更多优雅的艺术代码。
面向对象编程
面向对象编程就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法),这个对象我们称之为类。面向对象编程思想其中有一个特点就是封装,就是把你需要的功能放在一个对象里。遗憾的是对于JavaScript这种解释性的弱语言没有经典强类型语言中的那种通过class等关键字实现的类的封装方式,JavaScript中都是通过一些特性模仿实现的,但这也带来了极高的灵活性,让我们编写的代码更自由。
封装
创建一个类
var Book = function(id, bookName, price) {
this.id = id;
this.bookName = bookName;
this.price = price;
};
也可以通过在类的原型上添加属性跟方法
Book.prototype.display = function() {};
//或者
Book.prototype = {
display: function() {}
};
//不要混用
这样我们所需要的方法跟属性都封装在我们抽象的Book类里面了,实例化对象并使用方法属性:
var book = new Book(01, 'JavaScript', 50);
console.log(book.bookName);//'JavaScript'
通过this添加的属性跟方法与通过prototype添加的区别在上面有写,可以回去查看。
在创建一个函数或者对象时候都会为其创建一个原型对象prototype,在prototype对象中又会想函数中创建this一样创建一个constructor属性,constructor属性指向的就是拥有整个原型对象的函数或者对象,例如上面的Book prototype中的constructor属性指向的就是Book类对象
属性与方法封装
但是在学校学习的面向对象思想,说的就是一些属性方法的隐藏与暴露,比如私有属性、私有方法、公有方法、公有属性、保护方法等等,但是这些在JavaScript中没有显性的存在,但是之前都说了JavaScript是一种灵活的语言,所以我们可以通过一些灵活的技巧来实现它。
var Book = function(id, name, price) {
//私有属性
var num = 1;
//私有方法
function checkId() {};
//特权方法
this.getname = function() {
return this.name;
};
this.getPrice = function() {
return this.price;
};
this.setName = function(name) {
this.name = name;
};
this.setPrice = function(price) {
this.price = price;
};
//公有属性
this.id = id;
//公有方法
this.copy = function() {};
//构造器
this.setName(name);
this.setPrice(price);
};
//类静态公有属性(对象不能访问)
Book.isChinese = true;
//类静态公有方法(对象不能访问)
Book.resetTime = function() {};
//公有属性
Book.prototype.isJsBook = true;
//公有方法
Book.prototype.display = function() {};
由于JavaScript的函数级作用域,声明在函数内部的变量以及方法在外界是访问不到的,所以就可以创建私有变量以及私有方法。通过函数内部通过this以及通过原型prototype创建的属性与方法,在类创建对象时候,每个对象都是可以访问到的,因此可看作公有属性与公有方法,而且还能访问到类(创建时)或对象自身的私有属性与方法,由于这些方法权利比较大,所以又看做特权方法。在对象创建时通过使用这些特权方法可以初始化实例对象的一些属性,所以这些在创建对象时候调用的特权方法可以看作是类的构造器。
闭包实现
var Book = (function(){
//静态私有变量
var bookNum = 0;
//静态私有方法
function checkBook(name) {};
//返回构造函数
return function(newId, newName, newPrice) {
//私有属性
var name, price;
//私有方法
function checkId(id) {};
//特权方法
this.getname = function() {
return name;
};
this.getPrice = function() {
return price;
};
this.setName = function(newName) {
name = newName;
};
this.setPrice = function(newPrice) {
price = newPrice;
};
//公有属性
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() {},//静态公有方法
}
闭包是有权访问另外一个函数作用域中变量的函数,即在一个函数内部创建另外一个函数。将这个闭包作为创建对象的构造函数,这样它既是闭包又是可实例化对象的函数。但是在闭包外面添加原型属性和方法就显得脱离了闭包这个类,所以可以如下改造:
var Book = (function(){
//静态私有变量
var bookNum = 0;
//静态私有方法
function checkBook(name) {};
//返回构造函数
function _book(newId, newName, newPrice) {
//私有属性
var name, price;
//私有方法
function checkId(id) {};
//特权方法
this.getname = function() {
return name;
};
this.getPrice = function() {
return price;
};
this.setName = function(newName) {
name = newName;
};
this.setPrice = function(newPrice) {
price = newPrice;
};
//公有属性
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(id, name, price) {
//判断执行过程中this是否是当前这个对象(如果是就代表是new创建的)
if(this instanceof Book) {
this.id = id;
this.name = name;
this.price = price;
} else {
return new Book(id, name, price)
}
};
这样再去实例化对象时候不管是
var book = Book(01, 'JS', 50);
还是
var book = new Book(01, 'JS', 50);
book是当前类的一个实例化对象了。
结语
了解了JavaScript语言的灵活性,以及使用这个灵活性来实现面向对象思想,此篇文章仅分享到这,关于 JavaScript类的继承会拿出来在下一篇文章中单独分享。