看板 KnucklesNote
作者 標題 [JS] 克服JS的奇怪部分 ch9 來打造一個框架/資源庫!
時間 2016-12-12 Mon. 00:58:57
Udemy課程: JavaScript全攻略:克服JS的奇怪部分
https://www.udemy.com/javascriptjs/learn/v4/overview
上完第九章的心得筆記
章節9 來打造一個框架/資源庫!
73. 需求
框架命名: Greetr
輸入姓名,選擇性輸入語言
產生正式和非正式的問候
語言支援 English 和 Spanish
必需能重覆使用,不會跟其他JS程式衝突
可用簡寫 G$() 來執行
支援 jQuery
74. 打造安全的程式
先建立一個 HTML 檔,會載入 jQuery、Greetr.js、app.js 三個JS檔
<html>
<head>
</head>
<body>
<script src="jquery-1.11.2.js"></script>
<script src="Greetr.js"></script>
<script src="app.js"></script>
</body>
</html>
我們要打造的框架會寫在 Greetr.js<head>
</head>
<body>
<script src="jquery-1.11.2.js"></script>
<script src="Greetr.js"></script>
<script src="app.js"></script>
</body>
</html>
在 Greetr.js 中,我們首先要用立即執行函數
將我們的框架程式全部包起來,讓他有一個安全的執行環境
避免與全域環境衝突
在這個執行環境產生時,要傳入全域物件 window,以及 jQuery 物件
(function(global, $){
})(window, jQuery);
// 框架程式內容
})(window, jQuery);
75. 我們的物件與其原型
我們希望在建立 Greetr 物件時,可以像 jQuery 那樣執行一個函數即可
不需要加上 new 運算子,像這樣
var g = G$(firstName, lastName, language);
所以在 Greetr.js 中,我們要將 Greetr 建立為一個一般函數
然後在 Greetr 函數中再使用函數建構子來產生一個物件
函數建構子要將能輸入三個參數 firstName, lastName, language
若沒輸入時要有預設值
在函數建構子中將這三個輸入值設定為建立物件的屬性
試著依照 jQuery 的模式寫寫看,結果會像這樣
(function(global, $){
})(window, jQuery);
將 Greetr 建立為一般函數,會輸入三個參數var Greetr = function(firstName, lastName, language){
return new Greetr.init(firstName, lastName, language);
}
Greetr.init = function(firstName, lastName, language){
var self = this;
self.firstName = firstName || '';
self.lastName = lastName || '';
self.language = language || 'en';
}
})(window, jQuery);
在函數裡用函數建構子 Greetr.init 建立物件
接著建立函數建構子 Greetr.init
先將產生物件的 this 存成 self
然後將三個輸入值存成物件的屬性
再來我們想要在一般函數 Greetr 的屬性 prototype 中加上一些函數
Greetr.prototype = {
// ...
}
讓產生的物件可以從原型呼叫這些函數來用
但物件實際上是由函數建構子 Greetr.init 產生的
物件的原型會指向 Greetr.init.prototype
所以要將 Greetr.init.prototype 改成指向 Greetr.prototype
Greetr.init.prototype = Greetr.prototype;
然後將 Greetr 函數存成全域變數 Greetr 與 G$
global.Greetr = global.G$ = Greetr;
加進程式後變成像這樣
(function(global, $){
})(window, jQuery);
var Greetr = function(firstName, lastName, language){
return new Greetr.init(firstName, lastName, language);
}
Greetr.prototype = {
// ...
}
Greetr.init = function(firstName, lastName, language){
var self = this;
self.firstName = firstName || '';
self.lastName = lastName || '';
self.language = language || 'en';
}
Greetr.init.prototype = Greetr.prototype;
global.Greetr = global.G$ = Greetr;
})(window, jQuery);
現在我們可以在 app.js 中使用 G$ 建立 Greetr 物件了
var g = G$('John', 'Doe');
console.log(g);
執行結果console.log(g);
![[圖]](http://i.imgur.com/XfYz76j.png)
76. 屬性與可鍵結方法
接下來幫 Greetr 加上一些功能
之前我們在函數建構子 Greetr.init 中,使用 self 建立的三個物件屬性,
這些屬性在每個新建立的物件都會另外存一份,
每個產生的物件儲存的屬性值可以不相同
為了節省記憶體空間,如果我們想要有些屬性或成員函數是所有產生的物件共享的,
那應該要放在哪裡呢
如果有某些變數我只想在框架程式中使用,不想被外面的程式取用,
建立物件時,也不會變成物件的一部份,
要放在哪邊呢
參考以下程式
(function(global, $) {
}(window, jQuery));
在建立完 Greetr 函數後,接著建立一些只有在框架中可使用的變數var Greetr = function(firstName, lastName, language) {
return new Greetr.init(firstName, lastName, language);
}
//只有在框架中使用,不讓外面程式取用的變數:
var supportedLangs = ['en', 'es']; //可使用的語言
var greetings = { //不同語的招呼語
en: 'Hello',
es: 'Hola'
};
var formalGreetings = { //不同語言的正式招呼語
en: 'Greetings',
es: 'Saludos'
};
var logMessages = { //不同語言的log訊息
en: 'Logged in',
es: 'Inició sesión'
};
Greetr.prototype = {
//建立的物件會共用的成員函數:
fullName: function() {
return this.firstName + ' ' + this.lastName;
},
validate: function() {
if (supportedLangs.indexOf(this.language) === -1) {
throw "Invalid language";
}
},
greeting: function() {
return greetings[this.language] + ' ' + this.firstName + '!';
},
formalGreeting: function() {
return formalGreetings[this.language] + ', ' + this.fullName();
},
greet: function(formal) {
var msg;
// if undefined or null it will be coerced to 'false'
if (formal) {
msg = this.formalGreeting();
}
else {
msg = this.greeting();
}
if (console) {
console.log(msg);
}
// 'this' refers to the calling object at execution time
// makes the method chainable
return this;
},
log: function() {
if (console) {
console.log(logMessages[this.language] + ': ' + this.fullName());
}
return this;
},
setLang: function(lang) { //改變要使用的語言
this.language = lang;
this.validate();
return this;
}
};
Greetr.init = function(firstName, lastName, language) {
var self = this;
self.firstName = firstName || '';
self.lastName = lastName || '';
self.language = language || 'en';
}
Greetr.init.prototype = Greetr.prototype;
global.Greetr = global.G$ = Greetr;
}(window, jQuery));
supportedLangs 使用陣列存了兩個可以使用的語言
var supportedLangs = ['en', 'es'];
greetings 為了要使用不同語言做為索引,所以使用物件來存兩種招呼語
var greetings = {
en: 'Hello',
es: 'Hola'
};
接著的 formalGreetings 與 logMessages 也是用物件來存兩種語言的字串
這幾個變數只有在整個立即執行函數的範圍裡可以存取
外面的程式無法直接取用這幾個變數
接下來在 Greetr.prototype = { ... } 中,
加上要讓建立的物件可以共用的成員函數
因為 Greetr.prototype 之後會覆寫到函數建構子 Greetr.init 的原型上
Greetr.init.prototype = Greetr.prototype;
所以用函數建構子 Greetr.init 建立的物件
可透過原型鍵使用 Greetr.prototype 中建立的函數
例如建立一個函數 fullName,用來取得屬性 firstName 與 lastName
fullName: function() {
return this.firstName + ' ' + this.lastName;
},
使用 this 可以讀取到建立物件時存進去的屬性
建立一個函數 validate,用來檢查建立物件時輸入的語言是否支援
validate: function() {
if (supportedLangs.indexOf(this.language) === -1) {
throw "Invalid language";
}
},
這邊可以取用到上面建立的 supportedLangs = ['en', 'es'];
是因為閉包的關係,變數會保留著,等到呼叫時還是可以取用
後面幾個函數 greet, log, setLang 最後會 return this;
是為了能使用方法鍵連續呼叫成員函數
在 Greetr.js 加上這一堆功能後,在 app.js 使用看看
var g = G$('John', 'Doe');
g.greet(); //顯示 Hello John!
//可以在執行完一個成員函數後,再直接執行另一個
g.greet() //顯示 Hello John!
.greet(true); //顯示 Greetings, John Doe
g.greet() //顯示 Hello John!
.setLang('es') //設定要顯示的語言
.greet(true); //顯示 Saludos, John Doe
//設定為不支援的語言
g.setLang('fr') //顯示錯誤 Uncaught Invalid language
.greet(); //這行不會執行
g.greet(); //顯示 Hello John!
//可以在執行完一個成員函數後,再直接執行另一個
g.greet() //顯示 Hello John!
.greet(true); //顯示 Greetings, John Doe
g.greet() //顯示 Hello John!
.setLang('es') //設定要顯示的語言
.greet(true); //顯示 Saludos, John Doe
//設定為不支援的語言
g.setLang('fr') //顯示錯誤 Uncaught Invalid language
.greet(); //這行不會執行
77. 增加 jQuery 支援
之前寫的 greet() 是將招呼語顯示在開放者工具的 Console 上
在這一節我們利用 jQuery 將招呼語顯示在網頁上
在網頁上加上要用來顯示招呼語的元件,例如
<h1 id="greeting"></h1>
我們希望在 app.js 中,執行 Greetr 物件的 HTMLGreeting()
將招呼語顯示在網頁的 <h1 id="greeting"></h1> 元件上
像這樣
var g = G$('John', 'Doe');
g.HTMLGreeting('#greeting', true); //在網頁的<h1>顯示 Greetings, John Doe
g.HTMLGreeting('#greeting', true); //在網頁的<h1>顯示 Greetings, John Doe
修改 Greetr.js 在 Greetr.prototype = { ... } 中新增一個函數
HTMLGreeting: function(selector, formal) {
if (!$) {
throw 'jQuery not loaded';
}
if (!selector) {
throw 'Missing jQuery selector';
}
var msg;
if (formal) {
msg = this.formalGreeting();
}
else {
msg = this.greeting();
}
$(selector).html(msg);
return this;
}
函數 HTMLGreeting 有兩個輸入值if (!$) {
throw 'jQuery not loaded';
}
if (!selector) {
throw 'Missing jQuery selector';
}
var msg;
if (formal) {
msg = this.formalGreeting();
}
else {
msg = this.greeting();
}
$(selector).html(msg);
return this;
}
第一個輸入值 selector 是給 jQuery 用來找出網頁元件的選擇器字串
例如我們要找出 id="greeting" 的元件,就傳入 "#greeting"
第二個輸入值 formal 是個布林值代表要用正式還是非正式的招呼語
先檢查 jQuery 物件 $ 有沒有值,輸入值 selector 有沒有值
接著依照 formal 的值選擇要執行 formalGreeting() 還是 greeting()
來取得招呼語 msg
取得招呼語 msg 後執行 $(selector).html(msg);
先用 $(selector) 取得網頁元件轉為 jQuery 物件後
使用 jQuery 的函數 html() 將 msg 填入網頁的元件中
最後加上 return this; 讓這個函數可使用方法鏈
79. 來使用我們的框架吧
使用 jQuery 以及 Greetr 來實作一個簡單的登入網頁
http://knuckles.disp.cc/test/jsWeirdPart/ch9/79/
在網頁上有一個選擇框,可以選擇 English 或 Spanish
有一個按鈕 Login,點擊按鈕後會隱藏選擇框和按鈕
然後顯示招呼語 (假設已經知道使用者的名稱了)
網頁的HTML為
<html>
<head>
</head>
<body>
<div id="logindiv">
<select id="lang">
<option value="en">English</option>
<option value="es">Spanish</option>
</select>
<input type="button" value="Login" id="login" />
</div>
<h1 id='greeting'></h1>
<script src="jquery-1.11.2.js"></script>
<script src="Greetr.js"></script>
<script src="app.js"></script>
</body>
</html>
<head>
</head>
<body>
<div id="logindiv">
<select id="lang">
<option value="en">English</option>
<option value="es">Spanish</option>
</select>
<input type="button" value="Login" id="login" />
</div>
<h1 id='greeting'></h1>
<script src="jquery-1.11.2.js"></script>
<script src="Greetr.js"></script>
<script src="app.js"></script>
</body>
</html>
在 app.js 中實作我們想要的功能
// 使用 jQuery 在 Login 按鈕的點擊事件執行一個匿名函數
$('#login').click(function() {
//建立一個 Greetr 物件 (假設我們已取得使用者的名字了)
var loginGrtr = G$('John', 'Doe');
//隱藏選擇框和按鈕
$('#logindiv').hide();
//執行 loginGrtr 物件的成員函數
loginGrtr.setLang($('#lang').val()) //取得選擇框的值,傳入 setLang()
.HTMLGreeting('#greeting', true) //在<h1>顯示招呼語
.log(); //在Console顯示執行記錄
});
$('#login').click(function() {
//建立一個 Greetr 物件 (假設我們已取得使用者的名字了)
var loginGrtr = G$('John', 'Doe');
//隱藏選擇框和按鈕
$('#logindiv').hide();
//執行 loginGrtr 物件的成員函數
loginGrtr.setLang($('#lang').val()) //取得選擇框的值,傳入 setLang()
.HTMLGreeting('#greeting', true) //在<h1>顯示招呼語
.log(); //在Console顯示執行記錄
});
--
※ 作者: Knuckles 時間: 2016-12-12 00:58:57
※ 編輯: Knuckles 時間: 2016-12-12 23:19:59
※ 看板: KnucklesNote 文章推薦值: 0 目前人氣: 0 累積人氣: 1413
回列表(←)
分享