摘要:組合使用構造函數模式和原型。構造函數用于定義實例屬性,原型鏈用于定定方法和共享的屬性。為了避免矛盾和意外的結果總是指定基數參數。
原型對象與原型鏈本文主要記錄平時開發遇到的知識點和小技巧
JavaScritp 引擎在訪問對象的屬性時,如果在對象本身中沒有找到,則會去原型鏈中查找,如果找到,直接返回值,如果整個鏈都遍歷且沒有找到屬性,則返回 undefined.原型鏈一般實現為一個鏈表,這樣就可以按照一定的順序來查找。
原型鏈是一個由對象組成的有限對象鏈,實現繼承和共享屬性。
var base = { name: "base", getInfo: function() { return this.name; }, getMoreInfo: function() { return this.id + ":" + this.name; } } var ext1 = { id: 0, name: "ext1" __proto__: base } var ext2 = { id: 9, __proto__: base } var ext3 = { id: 10, __proto__: base } console.log(ext1.id); // 0 console.log(ext1.getInfo()); // ext1 console.log(ext2.id); // 9 console.log(ext2.getInfo()); // base console.log(ext3.id); // 10 console.log(ext3.getMoreInfo()); // 10:base //getMoreInfo與getInfo 函數中的 this 表示原始對象,而并非原型對象.
// 構造函數,所有創建的對象都會有y屬性 function Foo(y) { this.y = y; } // 創建共享屬性x Foo.prototype.x = 10; // 創建共享方法calculate Foo.prototype.calculate = function(z) { return this.x + this.y + z; } // 使用foo模式創建b、c var b = new Foo(10); // 此時b.y為10 var c = new Foo(20); // 此時c.y為20 //b、c分別調用共享方法 console.log(b.calculate(10)); // 30 console.log(c.calculate(10)); // 40 // 注意一點,this這個值在一個繼承機制中,仍然是指向它原本屬于的對象,而不是從原型鏈上找到它時, 它所屬于的對象。
function Person() {}; Person.prototype = { constructor: Person, name: "Nicholas", age: 29, job: "Software Engineer", friends: ["Shelby", "Court"], sayName: function() { alert(this.name); } }; var person1 = new Person(); var person2 = new Person(); person1.friends.push("Grey"); console.log(person1.friends); // ["Shelby", "Court", "Grey"] console.log(person2.friends); // ["Shelby", "Court", "Grey"] console.log(person1.friends === person2.friends); // true 原型對象的問題,公共屬性可能會被篡改。這也是為什么很少看到有人使用原型鏈的原因。
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.friends = ["Shelby", "Court"]; } Person.prototype = { constructor: Person, sayName: function() { alert(this.name); } } var person1 = new Person(); var person2 = new Person(); person1.friends.push("Grey"); console.log(person1.friends); // ["Shelby", "Court", "Grey"] console.log(person2.friends); // ["Shelby", "Court"] //組合使用構造函數模式和原型。 //構造函數用于定義實例屬性,原型鏈用于定定方法和共享的屬性。數值轉換
使用 parseInt()你可以從字符串中獲取數值,該方法接受另一個基數參數,可以省略,但不推薦。
當字符串以0開頭的時候,就有可能會出問題。
例如,部分時間進入表單域,在ECMAScript 3中,開頭為”0′′ 的字符串被當做8進制處理了,但這已在ECMAScript 5中改變了。為了避免矛盾和意外的結果,總是指定基數參數。
var month = "06", year = "09"; month = parseInt(month, 10); year = parseInt(year, 10);
此例中,如果你忽略了基數參數,如parseInt(year), 返回的值將是 0。
因為“09”被當做8進制(好比執 行 parseInt( year, 8 )), 而09在8進制中不是個有效數字。
替換方法是將字符串轉換成數字,包括:
+"08" // 8 Number("08") // 8 顯式轉換 "08" - 0 // 8 隱式轉換Module模式
1.模塊化,可重用
2.封裝了變量和function, 與全局的命名空間不接觸, 松耦合
3.只暴露可用public的方法,其它私有方法全部隱藏.
var Calculator = function (eq) { //這里可以聲明私有成員 var eqCtl = document.getElementById(eq); return { // 暴露公開的成員 add: function (x, y) { var val = x + y; eqCtl.innerHTML = val; } }; }; // 我們可以通過如下的方式來調用: var calculator = new Calculator("eq"); calculator.add(2, 2);
當然,我們也可以使用匿名函數來完成它,并且引用全局對象。
(function ($, YAHOO) { // 這里,我們的代碼就可以使用全局的jQuery對象了,YAHOO也是一樣 } (jQuery, YAHOO));
Module模式的一個限制就是所有的代碼都要寫在一個文件,但是在一些大型項目里,將一個功能分離成多 個文件是非常重要的,因為可以多人合作易于開發。
var blogModule = (function (my) { my.AddPhoto = function () { //添加內部代碼 }; return my; } (blogModule));
上面的代碼盡管可以執行,但是必須先聲明blogModule,然后再執行上面的擴展代碼,也就是說步驟不 能亂,怎么解決這個問題呢?我們可以在傳入參數的時候進行一些改變:
var blogModule = (function (my) { // 添加一些功能 return my; } (blogModule || {}));
通過這樣的代碼,每個多帶帶分離的文件都保證這個結構,那么我們就可以實現任意順序的加載。
自執行函數在JavaScript里,任何function在執行的時候都會創建一個執行上下文。
因為為function聲明的變量和 function有可能只在該function內部,這個上下文,在調用function的時候,提供了一種簡單的方式來創 建自由變量 或 私有的子function。
當你聲明一個函數的時候,通過在后面加個括弧就可以實現自執行:
// 因為想下面第一個聲明的function可以在后面加一個括弧()就可以自己執行了,比如foo(), // 因為foo僅僅是function() { /* code */ }這個表達式的一個引用 var foo = function(){ /* code */ } // ...是不是意味著后面加個括弧都可以自動執行? function(){ /* code */ }(); // SyntaxError: Unexpected token // 但是如果你在括弧()里傳入一個表達式,將不會有異常拋出 // 但是foo函數依然不會執行 function foo(){ /* code */ }( 1 ); // 因為它完全等價于下面這個代碼,一個function聲明后面,又聲明了一個毫無關系的表達式: function foo(){ /* code */ }(1);
那么想要運行自執行函數有很多種方法:
(function () { /* code */ } ()); // 推薦使用這個 (function () { /* code */ })(); // 但是這個也是可以用的 // 由于括弧()和 JS的 &&,異或,逗號等操作符是在函數表達式和函數聲明上消除歧義的 // 所以一旦解析器知道其中一個是表達式了,其它的也都默認為表達式. // 比如: var i = function () { return 10; }(); true && function () { /* code */ }(); 0, function () { /* code */ }();
如果你不在意返回值,或者不怕難以閱讀, 甚至可以在function前面加一元操作符號:
!function () { /* code */ } (); ~function () { /* code */ } (); -function () { /* code */ } (); +function () { /* code */ } (); // 使用new關鍵字,也可以用 new function () { /* code */ } new function () { /* code */ } () // 如果需要傳遞參數,只需要加上括弧()自執行匿名函數的應用
自執行匿名函數應用最多的場景可能就是閉包了。
閉包可以創建額外的scope,這可以被用來組合相關的或有依賴性的代碼。用這種方式可以最大限度地減少代碼干擾的危害。但是濫用閉包也會產生一系列的副作用,比如內存泄露。在實際開發中,我們應該合理的應用閉包。
看一個例子:
for (var i=1; i<=5; i++) { setTimeout( function() { console.log(i); }, i * 1000 ); }
這是一個經典的閉包題,我們想要的結果其實是輸出1-5,可是卻發現輸出的是5個6.
那是因為javascript是單線程,執行代碼是以輪詢的形式進行執行。
換句話說,setTimeout函數的代碼,被放到了第二梯隊,第一梯隊是執行for循環,循環完畢之后,才會執行setTimeout里的function。
所以當for循環執行完畢之后,i的值已經是6了。
那么我們可以用匿名函數閉包來解決這個問題:
for (var i=1; i<=5; i++) { (function(i) { setTimeout( function() { console.log(i); }, i*1000 ); })(i) }
在setTimeout的外層包裹一個自執行匿名函數,并傳入i,根據閉包的特性,此時每次循環時的i值都保存在對應的閉包中,而不在受到外層i的影響,setTimeout里的function中輸出的i值,訪問的是其對應閉包中的值。
這個題目是考閉包的,其實我們使用值的傳遞,一樣可以得到同樣的結果,只不過那樣的話,可能就不是考官想要的答案了。
for (var i=1; i<=5; i++) { setTimeout( function(i) { console.log(i); }, i*1000 ,i); }
我們知道,函數的參數如果是普通類型值,是按值傳遞的。因此可以取巧,直接傳值,來得到想要的答案。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/84748.html
摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...
Web前端開發是創建Web頁面或app等前端界面呈現給用戶的過程。第一階段:前端基礎(HTML / CSS / JavaScript / jQuery)初識HTML+CSS【學習筆記】HTML基礎完結篇html基礎知識——標簽詳解html基礎知識——與用戶交互!(表單標簽)html基礎知識——css樣式①史上最全Html和CSS布局技巧面試題匯總 HTML+CSS篇CSS 最核心的幾個概念純HTM...
閱讀 2077·2023-04-25 21:11
閱讀 2967·2021-09-30 09:47
閱讀 2277·2021-09-24 09:48
閱讀 4434·2021-08-23 09:43
閱讀 899·2019-08-30 15:54
閱讀 566·2019-08-28 18:01
閱讀 1402·2019-08-27 10:55
閱讀 592·2019-08-27 10:55