项目经理分下来一个验证表单功能的任务,内容不多,仅需要验证用户名、邮箱、密码等。
function checkName(){
// 验证姓名
}
function checkEmail(){
// 验证邮箱
}
function checkPassword(){
// 验证密码
}
复制代码
这种面向过程的实现方式,然而在这种方式中,你会发现无端地在页面中添加了很多全局变量,而且不利于别人重复使用。一旦别人使用以前提供的方法,你就不能轻易地去修改这些方法,这不利于团队代码维护。因此你现在要接受咱们团队这边的编程风格——面向对象编程
「那我应该如何避免呢?」
var CheckObject = function(){
this.checkName = function(){
// 验证姓名
}
this.checkEmail = function(){
// 验证邮箱
}
this.checkPassword = function(){
// 验证密码
}
}
var a = new CheckObject();
a.checkEmail();
复制代码
「当然,你看,我们是把所有的方法放在函数内部了,通过 this 定义的,所以每一次通过 new 关键字创建新对象的时候,新创建的对象都会对类的 this 上的属性进行复制。所以这些新创建的对象都会有自己的一套方法,然而有时候这么做造成的消耗是很奢侈的,我们需要处理一下。」
var CheckObject = function(){};
CheckObject.prototype = {
checkName : function(){
// 验证姓名
},
checkEmail : function(){
// 验证邮箱
},
checkPassword : function(){
// 验证密码
}
}
复制代码
面向对象编程
「面向对象编程就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法)。这个对象我们称之为类。面向对象编程思想其中有一个特点就是封装,就是说把你需要的功能放在一个对象里。比如你大学毕业你来公司携带的行李物品没有一件一件拿过来,而是要将他们放在一个旅行箱里,这样不论携带还是管理都会更方便一些。遗憾的是对于 JavaScript 这种解释性的弱类型语言没有经典强类型语言中那种通过 class 等关键字实现的类的封装方式,JavaScript 中都是通过一些特性模仿实现的,但这也带来了极高的灵活性,让我们编写的代码更自由。」
「通过 this 添加的属性和方法同在 prototype 中添加的属性和方法有什么区别呀?」
「通过 this 添加的属性、方法是在当前对象上添加的,然而 JavaScript 是一种基于原型 prototype 的语言,所以每创建一个对象时(当然在 JavaScript 中函数也是一种对象),它都有一个原型 prototype 用于指向其继承的属性、方法。这样通过 prototype 继承的方法并不是对象自身的,所以在使用这些方法时,需要通过 prototype 一级一级查找来得到。这样你会发现通过 this 定义的属性或者方法是该对象自身拥有的,所以我们每次通过类创建一个新对象时,this 指向的属性和方法都会得到相应的创建,而通过 prototype 继承的属性或者方法是每个对象通过 prototype 访问到,所以我们每次通过类创建一个新对象时这些属性和方法不会再次创建。
「解析图中的 constructor 又是指的什么呀。」
「constructor 是一个属性,当创建一个函数或者对象时都会为其创建一个原型对象 prototype,在 prototype 对象中又会像函数中创建 this 一样创建一个 constructor 属性,那么 constructor 属性指向的就是拥有整个原型对象的函数或对象,例如在本例中 Book prototype 中的 constructor 属性指向的就是 Book 类对象。」
「那么在 JavaScript 中又是如何实现的呢?」
「通过 new 关键字创建的对象实质是对新对象 this 的不断赋值,并将 prototype 指向类的 prototype 所指向的对象,而类的构造函数外面通过点语法定义的属性方法是不会添加到新创建的对象上去的。因此要想在新创建的对象中使用 isChinese 就得通过 Book 类使用而不能通过 this,如 Book.isChinese,而类的原型 prototype 上定义的属性在新对象里就可以直接使用,这是因为新对象的 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.copy = function(){};
//构造器
this.setName(name);
this.setPrice(price);
};
复制代码
//类静态公有属性(对象不能访问)
Book.isChinese = true;
//类静态公有方法(对象不能访问)
Book.resetTime = function(){
console.log('new Tiem')
};
Book.prototype = {
//公有属性
isJSBook : false,
//公有方法
display : function(){}
}
复制代码
// 利用闭包实现
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.setPrice(price);
}
})();
Book.prototype = {
//静态公有属性
isJSBook : false,
//静态公有方法
display : function(){}
};
复制代码