首頁 > web前端 > js教程 > 主體

JavaScript使用封裝

高洛峰
發布: 2016-11-30 16:59:45
原創
970 人瀏覽過

基本封裝方法

請看下面的例子:

var Person = function(name,age){
  this.name = name;
  this.age = age || "未填写";
  this.hobbys = [];
}

Person.prototype = {
  sayName:function(){
    console.log(this.name);
  },
  sayAge:function(){
    console.log(this.age);
  },
  addHobby:function(hobbys){
    this.hobbys = this.hobbys.concat(hobbys);
  }
}

var person1 = new Person("Jane","20");
var person2 = new Person("TabWeng","21");

person1.addHobby(['sing','drawing']);
person2.addHobby(['football','study','running']);

person1.sayName();
console.log(person1.hobbys.toString());

person2.sayName();
console.log(person2.hobbys.toString());
登入後複製

運行結果:

Jane  
sing,drawing
TabWeng  
football,study,running
TabWeng  

football,study,running

和方法寫在原型上,需要每個實例各自都有的副本的屬性和方法放在建構函式中。

現在有個問題,名稱的輸入不能有數字,要怎麼解決呢?解決的方法可以寫一個檢查名稱的函數,這個函數寫在原型上。

var Person = function(name,age){
  //校验名称
  if(this.checkName(name)){
    throw new Error("名字 "+name+" 不能存在数字");
  }
  this.name = name;
  this.age = age || "未填写";
  this.hobbys = [];
}

Person.prototype = {
  //校验函数
  checkName:function(name){
    re = /\d/;
    return re.test(name);
  },
  sayName:function(){
    console.log(this.name);
  },
  sayAge:function(){
    console.log(this.age);
  },
  addHobby:function(hobbys){
    this.hobbys = this.hobbys.concat(hobbys);
  }
}

var person1 = new Person("Helen666","20");
var person2 = new Person("TabWeng","21");

person1.addHobby(['sing','drawing']);
person2.addHobby(['football','study','running']);

person1.sayName();
console.log(person1.hobbys.toString());

person2.sayName();
console.log(person2.hobbys.toString());
登入後複製

這段程式碼中,我們寫了一個checkName()函數,來校驗名稱,暫且只是校驗不能有數字吧,然後再建構函數裡的第一行程式碼中進行校驗,若校驗不通過,則拋出異常。
這裡我傳入一個名稱Helen666,結果拋出如下異常:

Error: 名字 Helen666 不能存在數字

這樣就做到了一個基本的封裝,實現內部校驗。

但是又有個問題,我們還可以這樣來定義名稱:

var person1 = new Person("Helen","20");
person1.name = "Helen666";
person1.sayName(); //Helen666
登入後複製

這樣名稱還是可以修改為不合法的名稱,於是我們想到用get方法 和set方法來做控制,只能透過set方法來賦值,同時透過set方法進行校驗,而透過get方法來獲得值。現在的程式碼修改如下:

// Interfacevar People = new Interface("People",["setName","getName","setAge","getAge","addHobby","getHobby","sayName","sayAge"]);var Person = function(name,age){ //implement People
  this.setName(name);
  this.setAge(age);
  this._hobbys = [];}Person.prototype = {
  //校验函数
  checkName:function(name){
    re = /\d/;
    return re.test(name);
  },
  sayName:function(){
    console.log(this._name);
  },
  sayAge:function(){
    console.log(this._age);
  },
  addHobby:function(hobbys){
    this._hobbys = this._hobbys.concat(hobbys);
  },
  getHobby:function(){
    return this._hobbys;
  },
  setName:function(name){
    if(this.checkName(name)){
      throw new Error("名字 "+name+" 不能含有数字");
    }
    this._name = name;
  },
  getName:function(){
    return this._name;
  },
  setAge:function(age){
    this._age = age || "未设置"; 
  },
  getAge:function(){
    return this._age;
  }}var person1 = new Person("Helen","20");person1.addHobby(['sing','drawing']);function record(person){
  Interface.ensureImplements(person,People);
  person.sayName();
  console.log(person.getHobby().toString());}record(person1);
登入後複製

運行結果:

Helen
sing,drawing

首先,這段程式碼我們使用了接口,定義了People接口,而person來實現這個接口,注意註釋的內容。 (關於介面,請看這篇 JavaScript使用介面)
其次,我們使用了get方法 和 set方法來取值和賦值,我們可以約定程式設計師只能透過set來賦值,而在set方法裡面我們對所賦予的值進行了校驗,以確保準確。但這只是一種約定,程式設計師依然可以透過 person1.name = "123" 來賦值,修改內部屬性。
為了規範和起到提醒作用,我們把內部屬性的命名進行規範,在這些屬性前面加上“_”,比如**_name** 、**_age** ,這樣如果程式設計師要直接修改屬性,那麼他就必須這樣寫person1._name = "123",這明顯是一種故意的做法,一般程式設計師不會這麼做,起到規範和提醒的作用。

儘管如此,這種僅僅是用規定進行約束,還是無法阻止透過person1._name進行修改,下面的方法可以做到把內部屬性真正做到私有化。

透過閉包進行封裝

// Interface
var People = new Interface("People",["setName","getName","setAge","getAge","addHobby","getHobby","sayName","sayAge"]);

var Person = function(name,age){ //implement People
  // 私有变量
  var _name,_age,_hobbys = [];

  this.addHobby = function(hobbys){
    _hobbys = _hobbys.concat(hobbys);
  },
  this.getHobby = function(){
    return _hobbys;
  },
  this.setName = function(name){
    if(this.checkName(name)){
      throw new Error("名字 "+name+" 不能含有数字");
    }
    _name = name;
  },
  this.getName = function(){
    return _name;
  },
  this.setAge = function(age){
    _age = age || "未设置"; 
  },
  this.getAge = function(){
    return _age;
  }

  this.setName(name);
  this.setAge(age);
}

Person.prototype = {
  checkName:function(name){
    re = /\d/;
    return re.test(name);
  },
  sayName:function(){
    console.log(this.getName());
  },
  sayAge:function(){
    console.log(this.getAge());
  }

}

var person1 = new Person("Helen","20");
person1.addHobby(['sing','drawing']);

function record(person){
  Interface.ensureImplements(person,People);
  person.sayName();
  console.log(person.getHobby().toString());
}

record(person1);
登入後複製

在建構函式中,屬性不使用this,外部也就無法存取到這個屬性,而閉包透過作用域鏈可以存取到這個屬性,那麼我們就透過閉包設定了為屬性賦值的唯一入口,從而起到了嚴格校驗這些屬性的作用。

儘管如此,在構造函數中定義方法很多時候是沒必要的,因為這樣每創建一個實例,就會產生一個方法的副本,這是需要內存支持的,所以在使用的過程中,如果能用上面的基本封裝方法,盡量用,除非對於私有屬性有非常嚴格的校驗要求才用閉包這種方法。


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板