JavaScript高級程式設計(第三版)學習筆記22、24、25章

来源:http://www.cnblogs.com/TwinklingZ/archive/2016/03/15/5280970.html
-Advertisement-
Play Games

也可以基於這一思路測試某個值是不是原生函數或正則表達式: 方法2、在聲明函數時指定適當的函數,這樣第一次調用函數不損失性能,在代碼首次載入時會損失性能 按下按鈕實際顯示的是undefined,並不會顯示Event handled。問題在於沒有保存handler.handleClick的環境,所以th


第22章,高級技巧

高級函數

安全的類型檢測

typeof會出現無法預知的行為 instanceof在多個全局作用域中並不能正確工作 調用Object原生的toString方法,會返回[Object NativeConstructorName]格式字元串。每個類內部都有一個[[Class]]屬性,這個屬性中就指定了上述字元串中的構造函數名。 原生數組的構造函數名與全局作用域無關,因此使用toString方法能保證返回一致的值,為此可以創建如下函數:
function isArray(value){
    return Object.prototype.toString.call(value) == "[object Array]";
}

也可以基於這一思路測試某個值是不是原生函數或正則表達式:

//判斷是否原生函數
function isFunction(value){
    return Object.prototype.toString.call(value) == "[object Function]";
}
//判斷是否原生函數
function isFunction(value){
    return Object.prototype.toString.call(value) == "[object RegExp]";
}
註:對於IE中以COM對象形式實現的任何函數,isFunction都將返回false,因為他們並不是js原生函數 註:Object的toString方法不能檢測非原生構造函數的函數名。

作用域安全的構造函數

對於構造函數,使用了new操作符,則首先創建一個新的對象,將this指針指向新創建的對象,如果沒有使用new操作符,則this指針會指向window對象,作用域安全的構造函數:
function Person(name,age,job){
    if(this instanceof Person){          //判斷this是否是正確的類型
        this.name = name;
        this.age = age;
        this.job = job;
    }else{
        return new Person(name,age,job);
    }
}

var per1 = Person("Nicholas",29,"Software Engineer");
alert(window.name);         //""
alert(per1.name);           //"Nicholas"

var per2 = new Person("Shelby",34,"Ergonomist");
alert(per2.name);           //"Shelby"
建議:推薦使用作用域安全的構造函數作為最佳實踐

惰性載入函數

對於多分支的if語句,有些時候並不需要每次都查詢if語句,例如createXHR函數:
function createXHR(){
    if(typeof XMLHttpRequest != "undefined"){
        return new XMLHttpRequest;
    }else if(typeof ActiveXObject != "undefined"){
        if(typeof arguments.callee.activeXString != "string"){
            var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;
            for(i=0,len=versions.length;i < len;i++){
                try{
                    new ActiveXObject(versions[i]);
                    arguments.callee.activeXString = versions[i];
                    break;
                }catch(ex){
                    //跳過
                }
            }
        }
        return new ActiveXObject(arguments.callee.activeXString);
    }else{
        throw new Error("No XHR Object available");
    }
}
需要每次都對瀏覽器進行檢測,根本沒有必要,只要檢測一次就足夠了。對於此情況,解決方案:惰性載入技巧 惰性載入表示函數分支只會執行一次。 方法1、在函數被調用時處理函數,在第一次調用時該函數會被覆蓋為另一個按合適方式執行的函數。
function createXHR(){
    if(typeof XMLHttpRequest != "undefined"){
        createXHR = function(){                             //將原函數覆蓋
            return new XMLHttpRequest();
        };
    }else if(typeof ActiveXObject != "undefined"){
        createXHR = function(){                             //將原函數覆蓋
            if(typeof arguments.callee.activeXString != "string"){
                var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;
                for(i=0,len=versions.length;i < len;i++){
                    try{
                        new ActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                        break;
                    }catch(ex){
                        //跳過
                    }
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        };
    }else{
        createXHR = function(){                           //將原函數覆蓋
            throw new Error("No XHR object available.");
        };
    }
    return createXHR();
}

方法2、在聲明函數時指定適當的函數,這樣第一次調用函數不損失性能,在代碼首次載入時會損失性能

var createXHR = (function(){
    if(typeof XMLHttpRequest != "undefined"){
        return function(){
            return new XMLHttpRequest();
        };
    }else if(typeof ActiveXObject != "undefined"){
        return function(){
            if(typeof arguments.callee.activeXString != "string"){
                var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp.3.0","MSXML2.XMLHttp"],i,len;
                for(i=0,len=versions.length;i < len;i++){
                    try{
                        new ActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                        break;
                    }catch(ex){
                        //跳過
                    }
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        };
    }else{
        return function(){
            throw new Error("No XHR object available.");
        };
    }
})();

函數綁定

函數綁定要創建一個函數,可以在特定的this環境中以指定參數調用另一個函數。該技巧常常和回調函數與事件處理程式一起使用。
var handler = {
    message : "Event handled",

    handleClick : function(event){
        alert(this.message);
    }
};

var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn,"click",handler.handleClick);      //按鈕按下顯示undefined,不顯示Event handled

按下按鈕實際顯示的是undefined,並不會顯示Event handled。問題在於沒有保存handler.handleClick的環境,所以this最後指向了DOM按鈕,而非handler(IE8中this指向window),可以使用閉包解決問題:

var handler = {
    message : "Event handled",

    handleClick : function(event){
        alert(this.message);
    }
};

var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn,"click",function(event){
    handler.handleClick(event);                                             //按鈕按下顯示Event handled 
});
問題:閉包難以理解和調試。 大部分js庫為此實現了可以將函數綁定到指定環境的函數,一般叫做bind() 簡單的bind函數,接收一個函數和環境,返回一個給定函數中調用給定函數的函數,並且將所有參數原封不動傳過去
//bind函數解決方案
function bind(fn,context){
    return function(){
        return fn.apply(context,arguments);
    };
}

調用方法:

EventUtil.addHandler(btn,"click",bind(handler.handleClick,handler));
ECMAScript5為所有函數定義了原生的bind函數,進一步簡化了操作。調用方法
EventUtil.addHandler(btn,"click",handler.handleClick.bind(handler));          //傳入作為this的對象

支持的瀏覽器:IE9+,Firefox4+,Chrome

函數柯里化

用於創建已經設置好了一個或多個參數的函數。基本方法和函數綁定一樣:使用閉包返回一個函數。區別:函數被調用時返回的函數還需要設置一些傳入參數。

防篡改對象

註意:一旦把對象定義為防篡改對象,將不可撤銷,跟定義了屬性的[[Configurable]]為false的結果差不多

不可擴展對象

使用Object.preventExtensions()方法,讓你不能再給對象添加屬性和方法
var person = { name : "name"};
Object.preventExtensions(person);

person.age = 28;
alert(person.age);          //undefined
Object.isExtensible可檢測對象是否可擴展

密封對象

密封對象不可擴展,而且已有成員的[[Configurable]]特性將被設置為false。意味著不能修改或刪除屬性和方法 使用Object.seal()方法密封對象,使用Object.isSealed()方法確定對象是否密封。
var person = { name : "name" };
alert(Object.isExtensible(person));             //true
alert(Object.isSealed(person));                 //false

Object.seal(person);
alert(Object.isExtensible(person));             //false
alert(Object.isSealed(person));                 //true

凍結對象

最嚴格防篡改級別。凍結對象既不可擴展,又是密封,對象的數據屬性的[[Writable]]特性會被設置為false。如果定義了[[Set]]函數,訪問器屬性仍然可寫。 使用Object.freeze()方法凍結對象,Object.isFrozen()方法檢測對象是否凍結。

高級定時器

js是單線程的,定時器僅僅只是計劃代碼在未來某個時間執行,執行時間並不確定。意思就是,js是單線程的,所有需要處理的代碼都要排到執行隊列中去,而定時器,只是在我們設定的時間之後將代碼添加到隊列中去,並不一定馬上執行代碼。

重覆定時器

setInterval定時器的功能缺陷:可能在代碼再次被添加到隊列中時,之前的代碼還沒有完成執行,結果導致代碼運行好幾次。js引擎足夠聰明,能避免這個問題,在使用setInterval時,僅當沒有定時器的任何其他代碼實例時,才將定時器代碼加入到隊列。不過,還是有問題,1、某些間隔會被跳過,多個定時器的代碼執行之間的間隔可能比預期小。 使用setTimeout方法(超時調用,執行一次後再定義一個,模擬迴圈)來定義重覆定時器可以避免這些缺點。

函數節流

函數節流背後的基本思想是指,某些代碼不可以在沒有間斷的情況連續重覆執行。第一次調用函數,創建一個定時器,在指定時間間隔之後運行代碼。當第二次調用函數時,會清除前一次的定時器並設置另一個,如果前一個已經執行過了,此操作無意義。然而,若前一個定時器尚未執行,其實就是將其替換為一個新的定時器。目的在於只有執行函數的請求停止了一段時間後才執行。

自定義事件

拖放

第24章,最佳實踐

可維護性

特性:

1、可理解 2、直觀 3、可適應 4、可擴展 5、可調試

代碼約定

1、可讀性
(1)使用若幹空格而非製表符進行縮進 (2)註釋 函數和方法:每個函數或方法都應該包含一個註釋,用於描述目的和用於完成任務所可能使用的演算法,參數意義,返回值 大段代碼:描述任務的註釋 複雜演算法:解釋如何做的註釋 Hack:因瀏覽器差異,js代碼通常會包含一些hack,這些需要註釋。
2、變數和函數命名
(1)變數名應為名詞 (2)函數名應以動詞開頭,getName(),返回布爾值的函數以is開頭,isEnable() (3)使用合乎邏輯的名字,不必擔心長度,長度問題可以使用後處理和壓縮。
3、變數類型透明
很容易忘記變數所應包含的數據類型。合適的命名方式可以一定程度上緩解問題。還有以下三種表示變數數據類型的方式。 (1)變數初始化 (2)使用匈牙利標記法來指定變數類型。即,在變數前加一個或多個字元表示變數類型。 (3)使用變數註釋
var found /*Boolean*/ = false;

鬆散耦合

1、解耦HTML/JavaScript
理想情況:HTML和JavaScript應完全分離,使用外部文件和DOM附加行為來包含JavaScript
2、解耦CSS/JavaScript
//CSS對於JavaScript的緊密耦合
element.style.color = "red";
element.style.backgroundColor = "blue";

//CSS對於JavaScript的鬆散耦合
elements.className = "edit";
3、解耦應用邏輯/事件處理程式

編程實踐

1、尊重對象所有權

意思是,不能修改不屬於自己的對象。就是說,不是自己創建或維護的對象,就不要更改它的屬性和方法,即 (1)不要為實例或原型添加屬性 (2)不要為實例或原型添加方法 (3)不要重定義已存在的方法

2、避免全局變數

最多創建一個全局變數

3、避免與null進行比較

4、使用常量

var Constants = {
    INVALID_VALUE_MSG:"Invalid value!",
    INVALID_VALUE_URL:"/errors/invalid.php"
};

function validate(value){
    if(!value){
        alert(Constants.INVALID_VALUE_MSG);
        location.href = Constants.INVALID_VALUE_URL;
    }
}

性能

註意作用域

1、避免全局查找 2、避免with語句

選擇正確方法

1、避免不必要的屬性查找 2、優化迴圈 (1)減值迭代在大多數情況下更高效,即迴圈從最大值開始 (2)簡化終止條件 (3)簡化迴圈體 (4)使用後測試迴圈,do-while迴圈 3、展開迴圈 當迴圈次數是確定的,消除迴圈並使用多次函數調用往往會更快。 Duff裝置。 4、避免雙重解釋

最小化語句

1、多變數聲明

//4個語句---浪費
var count = 5;
var color = "red";
var values = [1,2,3];
var now = new Date();

//一個語句
var count = 5;
    color = "red";
    values = [1,2,3];
    now = new Date();

2、插入迭代值

var name = values[i];
i++;
//合併
var name = values[i++];

3、使用數組和對象字面量

優化DOM操作

1、最小化現場更新(使用倉庫) 可以使用DocumentFragment,一次插入多項更改 2、使用innerHTML 對於大的DOM更改,innerHTML方法,比使用標準的DOM方法(createElements,appendChild之類)速度快的多。 3、使用事件代理 4、註意HTMLCollection

壓縮

代碼長度和配重

代碼長度:瀏覽器所需解析位元組數 配重:實際從伺服器傳送到瀏覽器的位元組數 1、文件壓縮(使用壓縮工具) 刪除額外空白 刪除所有註釋 縮短變數名 2、HTTP壓縮

第25章,新興API

requestAnimationFrame()

與動畫相關

Page VisibilityAPI

因不知道用戶是否正在與頁面交互而推出的,能夠讓開發人員知道頁面是否對用戶可見

Geolocation API

地理定位,navigator.geolocation對象。

File API

宗旨:為Web開發人員提供一種安全的方式,以便在客戶端訪問用戶電腦中的文件

FileReader類型

實現的是一種非同步文件讀取機制,方法: readAsText(file,encoding):以純文本形式讀取文件,保存到result屬性中,第二個參數可選 readAsDataURL(file):讀取文件並將文件以數據URI的形式保存到result屬性 readAsBinaryString(file):讀文件並將一個字元保存在result屬性,字元串中每個字元表示一位元組 readAsArrayBuffer(file):讀文件並將一個包含文件內容的ArrayBuffer保存在result屬性中

讀取部分內容

File對象支持slice方法

對象URL

也被稱為blob URL,指的是引用在File或Blob中的數據的URL

Web計時

Web Workers


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前面提到 ES5 對象屬性描述符,這篇看看對象的擴展、密封和凍結。 阻止對象擴展,讓一個對象變的不可擴展,也就是永遠不能再添加新的屬性 ES3 是沒有辦法阻止對象擴展的,定義對象後可以給對象添加任意屬性,如 ES5 的 Object.preventExtensions 則可以阻止給對象添加新屬性 如
  • 重現代碼 以上網頁代碼,在 IE10/11 中輸出如下 可以看到IE10/11克隆時竟然把值賦給了value,這是一個的bug。 其它瀏覽器輸出的均是空字元串。 判斷是否有該bug的函數提取如下
  • Atitit. atiJavaExConverter4js 新的特性 1.1. V1新特性1 1.2. V2 新特性1 2. Keyword1 3. Catch1 4. Convert n Throw ex2 5. --atiex2 Java ex convert Catch 不同的ex Try c
  • Atitit hre框架v5 新特性 HREv5 1. V5新特性 apiurl2="/wrmiServlet";1 2. V1 新特性1 3. V2 新特性 添加php版1 4. V3 新特性 callback_checkJavaEx(data);1 5. V4 新特性1 基礎實現 <script
  • 本文內容相當簡單,所以沒有發佈到博客園首頁,如果你不幸看到,那隻能是我這篇文章的榮幸,謝謝你的大駕光臨~
  • html5 視頻播放
  • 說明:用線性漸變創建圖像 語法: <linear-gradient> = linear-gradient([ [ <angle> | to <side-or-corner> ] ,]? <color-stop>[, <color-stop>]+) <side-or-corner> = [left |
  • iOS 4.0+ 使用英文字體 Helvetica Neue,之前的iOS版本降級使用 Helvetica 中文字體設置為華文黑體STHeiTi 預設數字字體是Helvetica Neue 需補充說明,華文黑體並不存在iOS的字體庫中(http://support.apple.com/kb/HT58
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...