js高階程式設計 - 溫故而知新

Hwg發表於2019-05-17

JavaScript 誕生於 1995 年。當時,它的主要目的是處理以前由伺服器端語言(如 Perl)負責的一些輸入驗證操作。在 JavaScript 問世之前,必須把表單資料傳送到伺服器端才能確定使用者是否 沒有填寫某個必填域,那你可能九年級木塊模組了是否輸入了無效的值。 Netscape Navigator 希望通過 JavaScript 來解決這個問題。 在人們普遍使用電話拔號上網的年代,能夠在客戶端完成一些基本的驗證任務絕對是令人興奮的。畢竟,撥號上網的速度之慢,導致了與伺服器的每一次資料交換事實上都成了對人們耐心的一次考驗。

1.一個完整的 JavaScript 實現應該由下列三個不同的部分組成:

  • 核心(ECMAScript)
  • 文件物件模型(DOM)
  • 瀏覽器物件模型(BOM)

2.script元素:

script元素定義了下列 6 個屬性:

  • async :可選。表示應該立即下載指令碼,但不應妨礙頁面中的其他操作,比如下載其他資源或 等待載入其他指令碼。只對外部指令碼檔案有效。
  • charset :可選。表示通過 src 屬性指定的程式碼的字符集。由於大多數瀏覽器會忽略它的值, 因此這個屬性很少有人用。
  • defer:可選。表示指令碼可以延遲到文件完全被解析和顯示之後再執行。只對外部指令碼檔案有 效。IE7 及更早版本對嵌入指令碼也支援這個屬性。
  • language:已廢棄。
  • src:可選
  • type:可選。

3.ECMAScript中的基本資料型別

基本資料型別:Undefined、Null、Boolean、Number 和 String。

4.基本資料和引用型別的值

  • 基本型別值在記憶體中佔據固定大小的空間,因此被儲存在棧記憶體中;
  • 從一個變數向另一個變數複製基本型別的值,會建立這個值的一個副本;
  • 引用型別的值是物件,儲存在堆記憶體中;
  • 包含引用型別值的變數實際上包含的並不是物件本身,而是一個指向該物件的指標;
  • 從一個變數向另一個變數複製引用型別的值,複製的其實是指標,因此兩個變數最終都指向同一個物件

5.引用型別

  • Object型別
  • Array型別
  • Date型別
  • RegExp型別
  • Function型別

函式內部屬性

  • arguments.callee:返回一個對函式的引用,該函式呼叫了當前函式。
function factorial(num) {
    if (num <= 1) {
        return 1;
    } else {
        return num * arguments.callee(num - 1)
    }
}

複製程式碼
  • arguments.callee.caller:返回正被執行的 Function 物件,也就是所指定的 Function 物件的正文。
function outer(){ 
 inner(); 
} 
function inner(){ 
 alert(arguments.callee.caller); 
} 
outer(); 
複製程式碼

6.垃圾收集

javascript含有自動垃圾收集機制。

垃圾收集的方法:

  • JavaScript 中最常用的垃圾收集方式是標記清除。

當變數進入環境(例如,在函式中宣告一個變數)時,就將這個變數標記為“進入環境”。從邏輯上講,永遠不能釋放進入環境的變數所佔用的記憶體,因為只要執行流進入相應的環境,就可能會用到它們。而當變數離開環境時,則將其標記為“離開環境”。

  • 另一種不太常見的垃圾收集策略叫做引用計數。

引用計數的含義是跟蹤記錄每個值被引用的次數。當宣告瞭一個變數並將一個引用型別值賦給該變數時,則這個值的引用次數就是 1。如果同一個值又被賦給另一個變數,則該值的引用次數加1。相反,如果包含對這個值引用的變數又取得了另外一個值,則這個值的引用次數減1。當這個值的引用次數變成0時,則說明沒有辦法再訪問這個值了,因而就可以將其佔用的記憶體空間回收回來。這樣,當垃圾收集器下次再執行時,它就會釋放那些引用次數為零的值所佔用的記憶體

var element = document.getElementById("some_element"); 
var myObject = new Object(); 
myObject.element = element; 
element.someObject = myObject; 
複製程式碼

這個例子在一個 DOM 元素(element)與一個原生 JavaScript 物件(myObject)之間建立了迴圈 引用。其中,變數 myObject 有一個名為 element 的屬性指向 element 物件;而變數 element 也有 一個屬性名叫 someObject 回指 myObject。由於存在這個迴圈引用,即使將例子中的 DOM 從頁面中 移除,它也永遠不會被回收。

為了避免類似這樣的迴圈引用問題,最好是在不使用它們的時候手工斷開原生 JavaScript 物件與DOM 元素之間的連線。例如,可以使用下面的程式碼消除前面例子建立的迴圈引用:

myObject.element = null; 
element.someObject = null; 
複製程式碼

7.subString、substr、slice之間的區別

  • stringObject.substring(start,stop)
  • stringObject.substr(start,length)
  • arrayObject.slice(start,end)

8.物件屬性型別

ECMAScript 中有兩種屬性:資料屬性和訪問器屬性。

  • 資料屬性 Configurable:表示能否通過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特 性,或者能否把屬性修改為訪問器屬性。像前面例子中那樣直接在物件上定義的屬性,它們的 這個特性預設值為 true。 Enumerable:表示能否通過 for-in 迴圈返回屬性。像前面例子中那樣直接在物件上定 義的屬性,它們的這個特性預設值為 true。 Writable:表示能否修改屬性的值。像前面例子中那樣直接在物件上定義的屬性,它們的 這個特性預設值為 true。 Value:包含這個屬性的資料值。讀取屬性值的時候,從這個位置讀;寫入屬性值的時候, 把新值儲存在這個位置。這個特性的預設值為 undefined。

  • 訪問屬性 Configurable:表示能否通過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特 性,或者能否把屬性修改為資料屬性。對於直接在物件上定義的屬性,這個特性的預設值為 true。 Enumerable:表示能否通過 for-in 迴圈返回屬性。對於直接在物件上定義的屬性,這 個特性的預設值為 true。 Get:在讀取屬性時呼叫的函式。預設值為 undefined。 Set:在寫入屬性時呼叫的函式。預設值為 undefined。

      使用訪問器屬性的常見方式,即設定一個屬性的值會導致其他屬性發生變化
    複製程式碼

9.建立物件的幾種模式

  • 工廠模式
function person(name,age){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.sayName = function(){
        console.log(this.name)
    }
    return o;
}

var p = person('張三',20);
p.sayName(); // 張三
複製程式碼
  • 建構函式模式
function Person(name,age){
    this.name = name;
    this.age = age;
    this.sayName = function(){
        console.log(this.name);
    }
}

var p = new Person('張三',20);
p.sayName(); // 張三
複製程式碼

New例項化物件會經歷以下4個步驟:

1. 建立新物件
2. 將建構函式的作用域複製給新物件
3. 執行建構函式的方法
4. 返回新物件
複製程式碼
  • 原型模式
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("Van");
alert(person1.friends); //"Shelby,Court,Van" 
alert(person2.friends); //"Shelby,Court,Van" 
alert(person1.friends === person2.friends); //true

複製程式碼
  • 組合建構函式模式和原型模式
function Person(name,age){
    this.name = name;
    this.age = age;
}
Person.prototype.sayName = function(){
    console.log(this.name)
};

var p = new Person('張三',10);
p.sayName(); // 張三
複製程式碼
  • 動態原型模式
function Person(name,age){
    this.name = name;
    this.age = age;
    
    if (typeof this.sayName != 'function') {
        Person.prototype.sayName = function(){
            console.log(this.name)
        };
    }
}

var p = new Person('張三',10);
p.sayName(); // 張三
複製程式碼
  • 寄生建構函式模式
function Person(name,age){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.sayName = function(){
        console.log(this.name)
    };
    return o;
}

var p = new Person('張三',10);
p.sayName(); // 張三
複製程式碼
  • 穩妥建構函式模式
function Person(name,age){
    var o = new Object();
    o.name = name;
    o.age = age;

    o.sayName = function(){
        console.log(name)
    };
    return o;
}

var p = Person('張三',10);
p.sayName(); // 張三
複製程式碼

跨域請求技術

  • CORS(Cross-Origin Resource Sharing,跨源資源共享)
  • 圖片Ping 最常用於跟蹤使用者點選頁面或動態廣告曝光次數
  • JSONP JSONP 是通過動態script元素(要了解詳細資訊,請參考第 13 章)來使用的,使用時可以為 src 屬性指定一個跨域 URL。這裡的script元素與js高階程式設計 - 溫故而知新元素類似,都有能力不受限制地從其他域 載入資源。因為 JSONP 是有效的 JavaScript 程式碼,所以在請求完成後,即在 JSONP 響應載入到頁面中 以後,就會立即執行。來看一個例子
function handleResponse(response){ 
 alert("You’re at IP address " + response.ip + ", which is in " + 
 response.city + ", " + response.region_name); 
} 
var script = document.createElement("script"); 
script.src = "http://freegeoip.net/json/?callback=handleResponse"; 
document.body.insertBefore(script, document.body.firstChild); 

複製程式碼
  • Comet
  • SSE(Server-Sent Events,伺服器傳送事件)
  • Web Sockets

物件防篡改

  • Object.preventExtensions():不可新增屬性和方法
  • Object.seal():不能刪除屬性和方法
  • Object.freeze():不可新增屬性和方法並且不能刪除屬性和方法

效能優化

  • 避免全域性查詢
  • 避免 with 語句
  • 避免不必要的屬性查詢

使用變數和陣列要比訪問物件上的屬性更有效率

  • 避免雙重解釋
//某些程式碼求值——避免!! 
eval("alert('Hello world!')"); 

//建立新函式——避免!! 
var sayHi = new Function("alert('Hello world!')"); 

//設定超時——避免!! 
setTimeout("alert('Hello world!')", 500); 

//已修正
alert('Hello world!'); 

//建立新函式——已修正
var sayHi = function(){ 
 alert('Hello world!'); 
}; 

//設定一個超時——已修正 
setTimeout(function(){ 
 alert('Hello world!'); 
}, 500); 
複製程式碼
  • 最小語句數
//一個語句 
var count = 5, 
    color = "blue", 
    values = [1,2,3], 
    now = new Date(); 

//只用一條語句建立和初始化陣列 
var values = [123, 456, 789]; 

//只用一條語句建立和初始化物件 
var person = { 
    name : "Nicholas", 
    age : 29, 
    sayName : function(){ 
       alert(this.name); 
    } 
}; 
複製程式碼
  • 優化迴圈

推薦個開發專用的筆記吧,我已經習慣在這寫文件筆記了。Hbook筆記

相關文章