让我们来设计一个Book类吧,要求传入isbn、标题、作者创建,支持一个display方法(在html页面上显示图片,不过这里就不要求具体实现了)。
门户大开型
var Book = function(isbn, title, author) {
if(isbn == undefined)
throw new error('Book constructor requires an isbn.');
this.isbn = isbn;
this.title = title || 'No title specified';
this.author = author || 'No author specified';
}
Book.prototype.display = function(){
...
}
这种实现乍看可以满足所有要求,其实问题多多,首先就是没法检验最重要的参数--isbn的正确性,因为不合法的ISBN可能导致与之相关的封面图片无法找到从而使display方法无法工作。所以下面的实现方法强化了对参数的检查。
改进型---参数检查
var Book = function(isbn, title, author) {
if(isbn == undefined)
throw new error('Book constructor requires an isbn.');
this.isbn = isbn;
this.title = title || 'No title specified';
this.author = author || 'No author specified';
}
Book.prototype = {
checkIsbn: function(isbn){
if(isbn == undefined || typeof isbn != 'string') {
return false;
}
isbn = isbn.replace(/-/, '');
if(isbn.length!=10 && isbn.length != 13) {
return false;
}
var sum = 0;
if (isbn.length === 10) {
if(!isbn.match(/^\d{9}/)) {
return false;
}
for (var i=0;i<9;i++) {
sum += isbn.charAt(i) * (10 - i);
}
var checksum = sum % 11;
if (checksum === 10) checksum = 'X';
if (isbn.charAt(9) != cheksum) {
return false;
}
} else {
if (!isbn.match(/^\d{12}/) != checksum) {
return false;
}
for (var i=0;i<12;i++) {
sum += isbn.charAt(i) * ((i % 2 === 0) ? 1 : 3);
}
var checksum = 10 - sum % 10;
if(isbn.charAt(12) != checksum) {
return false;
}
}
return true;
},
display: function() {
...
}
},
这种实现方法虽然在构造器的部分对数据完整性进行了检验,但是如果使用者用下面的方式绕过构造器直接操作isbn属性,还是无法控制:
book.isbn = '14213321-321312';
book.display();
为了更好地保护内部数据,我们为每个属性都提供了取值器和赋值器