成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

前端基本功-常見概念(三)

Steven / 865人閱讀

摘要:前端基本功常見概念一點(diǎn)這里前端基本功常見概念二點(diǎn)這里前端基本功常見概念三點(diǎn)這里超文本標(biāo)記語言,顯示信息,不區(qū)分大小寫升級(jí)版的,區(qū)分大小寫可擴(kuò)展標(biāo)記語言被用來傳輸和存儲(chǔ)數(shù)據(jù)規(guī)范采用異步方式加載模塊,模塊的加載不影響它后面語句的運(yùn)行。

前端基本功-常見概念(一) 點(diǎn)這里
前端基本功-常見概念(二) 點(diǎn)這里
前端基本功-常見概念(三) 點(diǎn)這里

1.HTML / XML / XHTML

html:超文本標(biāo)記語言,顯示信息,不區(qū)分大小寫

xhtml:升級(jí)版的html,區(qū)分大小寫

xml:可擴(kuò)展標(biāo)記語言被用來傳輸和存儲(chǔ)數(shù)據(jù)

2.AMD/CMD/CommonJs/ES6 Module

AMD:AMD規(guī)范采用異步方式加載模塊,模塊的加載不影響它后面語句的運(yùn)行。所有依賴這個(gè)模塊的語句,都定義在一個(gè)回調(diào)函數(shù)中,等到加載完成之后,這個(gè)回調(diào)函數(shù)才會(huì)運(yùn)行。

AMD是requirejs 在推廣過程中對(duì)模塊定義的規(guī)范化產(chǎn)出,提前執(zhí)行,推崇依賴前置。用define()定義模塊,用require()加載模塊,require.config()指定引用路徑等

首先我們需要引入require.js文件和一個(gè)入口文件main.js。main.js中配置require.config()并規(guī)定項(xiàng)目中用到的基礎(chǔ)模塊。

    /** 網(wǎng)頁中引入require.js及main.js **/
    
    
    
    /** main.js 入口文件/主模塊 **/
    // 首先用config()指定各模塊路徑和引用名
    require.config({
      baseUrl: "js/lib",
      paths: {
        "jquery": "jquery.min",  //實(shí)際路徑為js/lib/jquery.min.js
        "underscore": "underscore.min",
      }
    });
    // 執(zhí)行基本操作
    require(["jquery","underscore"],function($,_){
      // some code here
    });

引用模塊的時(shí)候,我們將模塊名放在[]中作為reqiure()的第一參數(shù);如果我們定義的模塊本身也依賴其他模塊,那就需要將它們放在[]中作為define()的第一參數(shù)。

    // 定義math.js模塊
    define(function () {
        var basicNum = 0;
        var add = function (x, y) {
            return x + y;
        };
        return {
            add: add,
            basicNum :basicNum
        };
    });
    // 定義一個(gè)依賴underscore.js的模塊
    define(["underscore"],function(_){
      var classify = function(list){
        _.countBy(list,function(num){
          return num > 30 ? "old" : "young";
        })
      };
      return {
        classify :classify
      };
    })
        
    // 引用模塊,將模塊放在[]內(nèi)
    require(["jquery", "math"],function($, math){
      var sum = math.add(10,20);
      $("#sum").html(sum);
    });

CMD:seajs 在推廣過程中對(duì)模塊定義的規(guī)范化產(chǎn)出,延遲執(zhí)行,推崇依賴就近

require.js在申明依賴的模塊時(shí)會(huì)在第一之間加載并執(zhí)行模塊內(nèi)的代碼:

    define(["a", "b", "c", "d", "e", "f"], function(a, b, c, d, e, f) { 
        // 等于在最前面聲明并初始化了要用到的所有模塊
        if (false) {
          // 即便沒用到某個(gè)模塊 b,但 b 還是提前執(zhí)行了
          b.foo()
        } 
    });

CMD是另一種js模塊化方案,它與AMD很類似,不同點(diǎn)在于:AMD 推崇依賴前置、提前執(zhí)行,CMD推崇依賴就近、延遲執(zhí)行。此規(guī)范其實(shí)是在sea.js推廣過程中產(chǎn)生的。

    /** CMD寫法 **/
    define(function(require, exports, module) {
        var a = require("./a"); //在需要時(shí)申明
        a.doSomething();
        if (false) {
            var b = require("./b");
            b.doSomething();
        }
    });
    

    /** sea.js **/
    // 定義模塊 math.js
    define(function(require, exports, module) {
        var $ = require("jquery.js");
        var add = function(a,b){
            return a+b;
        }
        exports.add = add;
    });
    // 加載模塊
    seajs.use(["math.js"], function(math){
        var sum = math.add(1+2);
    });

CommonJs:Node.js是commonJS規(guī)范的主要實(shí)踐者,它有四個(gè)重要的環(huán)境變量為模塊化的實(shí)現(xiàn)提供支持:module、exports、require、global。實(shí)際使用時(shí),用module.exports定義當(dāng)前模塊對(duì)外輸出的接口(不推薦直接用exports),用require加載模塊。

    // 定義模塊math.js
    var basicNum = 0;
    function add(a, b) {
      return a + b;
    }
    module.exports = { //在這里寫上需要向外暴露的函數(shù)、變量
      add: add,
      basicNum: basicNum
    }
    
    // 引用自定義的模塊時(shí),參數(shù)包含路徑,可省略.js
    var math = require("./math");
    math.add(2, 5);
    
    // 引用核心模塊時(shí),不需要帶路徑
    var http = require("http");
    http.createService(...).listen(3000);

commonJS用同步的方式加載模塊。在服務(wù)端,模塊文件都存在本地磁盤,讀取非常快,所以這樣做不會(huì)有問題。但是在瀏覽器端,限于網(wǎng)絡(luò)原因,更合理的方案是使用異步加載。

ES6 Module:ES6 在語言標(biāo)準(zhǔn)的層面上,實(shí)現(xiàn)了模塊功能,而且實(shí)現(xiàn)得相當(dāng)簡(jiǎn)單,旨在成為瀏覽器和服務(wù)器通用的模塊解決方案。其模塊功能主要由兩個(gè)命令構(gòu)成:export和import。export命令用于規(guī)定模塊的對(duì)外接口,import命令用于輸入其他模塊提供的功能。

/** 定義模塊 math.js **/
var basicNum = 0;
var add = function (a, b) {
    return a + b;
};
export { basicNum, add };

/** 引用模塊 **/
import { basicNum, add } from "./math";
function test(ele) {
    ele.textContent = add(99 + basicNum);
}

如上例所示,使用import命令的時(shí)候,用戶需要知道所要加載的變量名或函數(shù)名。其實(shí)ES6還提供了export default命令,為模塊指定默認(rèn)輸出,對(duì)應(yīng)的import語句不需要使用大括號(hào)。這也更趨近于ADM的引用寫法。

/** export default **/
//定義輸出
export default { basicNum, add };
//引入
import math from "./math";
function test(ele) {
    ele.textContent = math.add(99 + math.basicNum);
}

ES6的模塊不是對(duì)象,import命令會(huì)被 JavaScript 引擎靜態(tài)分析,在編譯時(shí)就引入模塊代碼,而不是在代碼運(yùn)行時(shí)加載,所以無法實(shí)現(xiàn)條件加載。也正因?yàn)檫@個(gè),使得靜態(tài)分析成為可能。

ES6 模塊與 CommonJS 模塊的差異

CommonJS 模塊輸出的是一個(gè)值的拷貝,ES6 模塊輸出的是值的引用。

CommonJS 模塊輸出的是值的拷貝,也就是說,一旦輸出一個(gè)值,模塊內(nèi)部的變化就影響不到這個(gè)值。

ES6 模塊的運(yùn)行機(jī)制與 CommonJS 不一樣。JS 引擎對(duì)腳本靜態(tài)分析的時(shí)候,遇到模塊加載命令import,就會(huì)生成一個(gè)只讀引用。等到腳本真正執(zhí)行時(shí),再根據(jù)這個(gè)只讀引用,到被加載的那個(gè)模塊里面去取值。換句話說,ES6 的import有點(diǎn)像 Unix 系統(tǒng)的“符號(hào)連接”,原始值變了,import加載的值也會(huì)跟著變。因此,ES6 模塊是動(dòng)態(tài)引用,并且不會(huì)緩存值,模塊里面的變量綁定其所在的模塊。

CommonJS 模塊是運(yùn)行時(shí)加載,ES6 模塊是編譯時(shí)輸出接口。

運(yùn)行時(shí)加載: CommonJS 模塊就是對(duì)象;即在輸入時(shí)是先加載整個(gè)模塊,生成一個(gè)對(duì)象,然后再從這個(gè)對(duì)象上面讀取方法,這種加載稱為“運(yùn)行時(shí)加載”。

- 編譯時(shí)加載: ES6 模塊不是對(duì)象,而是通過 export 命令顯式指定輸出的代碼,import時(shí)采用靜態(tài)命令的形式。即在import時(shí)可以指定加載某個(gè)輸出值,而不是加載整個(gè)模塊,這種加載稱為“編譯時(shí)加載”。


CommonJS 加載的是一個(gè)對(duì)象(即module.exports屬性),該對(duì)象只有在腳本運(yùn)行完才會(huì)生成。而 ES6 模塊不是對(duì)象,它的對(duì)外接口只是一種靜態(tài)定義,在代碼靜態(tài)解析階段就會(huì)生成。


本節(jié)參考文章:前端模塊化:CommonJS,AMD,CMD,ES6

3.ES5的繼承/ES6的繼承

ES5的繼承時(shí)通過prototype或構(gòu)造函數(shù)機(jī)制來實(shí)現(xiàn)。ES5的繼承實(shí)質(zhì)上是先創(chuàng)建子類的實(shí)例對(duì)象,然后再將父類的方法添加到this上(Parent.apply(this))。

ES6的繼承機(jī)制完全不同,實(shí)質(zhì)上是先創(chuàng)建父類的實(shí)例對(duì)象this(所以必須先調(diào)用父類的super()方法),然后再用子類的構(gòu)造函數(shù)修改this。

具體的:ES6通過class關(guān)鍵字定義類,里面有構(gòu)造方法,類之間通過extends關(guān)鍵字實(shí)現(xiàn)繼承。子類必須在constructor方法中調(diào)用super方法,否則新建實(shí)例報(bào)錯(cuò)。因?yàn)樽宇悰]有自己的this對(duì)象,而是繼承了父類的this對(duì)象,然后對(duì)其進(jìn)行加工。如果不調(diào)用super方法,子類得不到this對(duì)象。

ps:super關(guān)鍵字指代父類的實(shí)例,即父類的this對(duì)象。在子類構(gòu)造函數(shù)中,調(diào)用super后,才可使用this關(guān)鍵字,否則報(bào)錯(cuò)。

區(qū)別:(以SubClass,SuperClass,instance為例)

ES5中繼承的實(shí)質(zhì)是:(那種經(jīng)典寄生組合式繼承法)通過prototype或構(gòu)造函數(shù)機(jī)制來實(shí)現(xiàn),先創(chuàng)建子類的實(shí)例對(duì)象,然后再將父類的方法添加到this上(Parent.apply(this))。

先由子類(SubClass)構(gòu)造出實(shí)例對(duì)象this

然后在子類的構(gòu)造函數(shù)中,將父類(SuperClass)的屬性添加到this上,SuperClass.apply(this, arguments)

子類原型(SubClass.prototype)指向父類原型(SuperClass.prototype)

所以instance是子類(SubClass)構(gòu)造出的(所以沒有父類的[[Class]]關(guān)鍵標(biāo)志)

所以,instance有SubClass和SuperClass的所有實(shí)例屬性,以及可以通過原型鏈回溯,獲取SubClass和SuperClass原型上的方法

ES6中繼承的實(shí)質(zhì)是:先創(chuàng)建父類的實(shí)例對(duì)象this(所以必須先調(diào)用父類的super()方法),然后再用子類的構(gòu)造函數(shù)修改this

先由父類(SuperClass)構(gòu)造出實(shí)例對(duì)象this,這也是為什么必須先調(diào)用父類的super()方法(子類沒有自己的this對(duì)象,需先由父類構(gòu)造)

然后在子類的構(gòu)造函數(shù)中,修改this(進(jìn)行加工),譬如讓它指向子類原型(SubClass.prototype),這一步很關(guān)鍵,否則無法找到子類原型(注,子類構(gòu)造中加工這一步的實(shí)際做法是推測(cè)出的,從最終效果來推測(cè))

然后同樣,子類原型(SubClass.prototype)指向父類原型(SuperClass.prototype)

所以instance是父類(SuperClass)構(gòu)造出的(所以有著父類的[[Class]]關(guān)鍵標(biāo)志)

所以,instance有SubClass和SuperClass的所有實(shí)例屬性,以及可以通過原型鏈回溯,獲取SubClass和SuperClass原型上的方法

靜態(tài)方法繼承實(shí)質(zhì)上只需要更改下SubClass.__proto__到SuperClass即可

本節(jié)參考文章:鏈接

4.HTTP request報(bào)文/HTTP response報(bào)文
請(qǐng)求報(bào)文 響應(yīng)報(bào)文
請(qǐng)求行 請(qǐng)求頭 空行 請(qǐng)求體 狀態(tài)行 響應(yīng)頭 空行 響應(yīng)體

HTTP request報(bào)文結(jié)構(gòu)是怎樣的

首行是Request-Line包括:請(qǐng)求方法,請(qǐng)求URI,協(xié)議版本,CRLF
首行之后是若干行請(qǐng)求頭,包括general-header,request-header或者entity-header,每個(gè)一行以CRLF結(jié)束
請(qǐng)求頭和消息實(shí)體之間有一個(gè)CRLF分隔
根據(jù)實(shí)際請(qǐng)求需要可能包含一個(gè)消息實(shí)體 一個(gè)請(qǐng)求報(bào)文例子如下:

GET /Protocols/rfc2616/rfc2616-sec5.html HTTP/1.1
Host: www.w3.org
Connection: keep-alive
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36
Referer: https://www.google.com.hk/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6
Cookie: authorstyle=yes
If-None-Match: "2cc8-3e3073913b100"
If-Modified-Since: Wed, 01 Sep 2004 13:24:52 GMT

name=qiu&age=25

請(qǐng)求報(bào)文

HTTP response報(bào)文結(jié)構(gòu)是怎樣的

首行是狀態(tài)行包括:HTTP版本,狀態(tài)碼,狀態(tài)描述,后面跟一個(gè)CRLF
首行之后是若干行響應(yīng)頭,包括:通用頭部,響應(yīng)頭部,實(shí)體頭部
響應(yīng)頭部和響應(yīng)實(shí)體之間用一個(gè)CRLF空行分隔
最后是一個(gè)可能的消息實(shí)體 響應(yīng)報(bào)文例子如下:

HTTP/1.1 200 OK
Date: Tue, 08 Jul 2014 05:28:43 GMT
Server: Apache/2
Last-Modified: Wed, 01 Sep 2004 13:24:52 GMT
ETag: "40d7-3e3073913b100"
Accept-Ranges: bytes
Content-Length: 16599
Cache-Control: max-age=21600
Expires: Tue, 08 Jul 2014 11:28:43 GMT
P3P: policyref="http://www.w3.org/2001/05/P3P/p3p.xml"
Content-Type: text/html; charset=iso-8859-1

{"name": "qiu", "age": 25}

響應(yīng)報(bào)文

5.面向?qū)ο蟮墓S模式/構(gòu)造函數(shù)

工廠模式集中實(shí)例化了對(duì)象,避免實(shí)例化對(duì)象大量重復(fù)問題

//工廠模式
function createObject(a,b){
    var obj = new Object();    //集中實(shí)例化
    obj.a = a;
    obj.b = b;
    obj.c = function () {
        return this.a + this.b;
    };
    return obj;        //返回實(shí)例化對(duì)象
}
var box = createObject("abc",10);
var box1 = createObject("abcdef",20);
alert(box.c());        //返回abc10
alert(box1.c());       //返回abcdef20
//構(gòu)造函數(shù)
function Create(a,b) {
    this.a =a;
    this.b =b;
    this.c = function () {
        return this.a + this.b;
    };
}
var box = new Create("abc",10);
alert(box.run());    //返回abc10

構(gòu)造函數(shù)相比工廠模式:

沒有集中實(shí)例化

沒有返回對(duì)象實(shí)例

直接將屬性和方法賦值給this

解決了對(duì)象實(shí)例歸屬問題

構(gòu)造函數(shù)編寫規(guī)范:

構(gòu)造函數(shù)也是函數(shù),但是函數(shù)名的第一個(gè)字母大寫

必須使用new運(yùn)算符 + 函數(shù)名(首字母大寫)例如:var box = new Create();

構(gòu)造函數(shù)和普通函數(shù)的區(qū)別:

普通函數(shù),首字母無需大寫

構(gòu)造函數(shù),用普通函數(shù)調(diào)用方式無效

查看歸屬問題,要?jiǎng)?chuàng)建兩個(gè)構(gòu)造函數(shù):

function Create(a,b) {
    this.a =a;
    this.b =b;
    this.c = function () {
        return this.a + this.b;
    };
}

function DeskTop(a,b) {
    this.a =a;
    this.b =b;
    this.c = function () {
        return this.a + this.b;
    };
}

var box = new Create("abc",10);
var box1 = new DeskTop("def",20);
alert(box instanceof Object);
//這里要注意:所有的構(gòu)造函數(shù)的對(duì)象都是Object.
alert(box instanceof Create);    //true
alert(box1 instanceof Create);   //false
alert(box1 instanceof DeskTop);    //true
6. new Promise / Promise.resolve()

Promise.resolve()可以生成一個(gè)成功的Promise

Promise.resolve()語法糖

例1:
Promise.resolve("成功")等同于new Promise(function(resolve){resolve("成功")})

例2:

var resolved = Promise.resolve("foo");

resolved.then((str) => 
    console.log(str);//foo
)

相當(dāng)于

var resolved = new Promise((resolve, reject) => {
   resolve("foo")
});

resolved.then((str) => 
    console.log(str);//foo
)

Promise.resolve方法有下面三種形式:

Promise.resolve(value);

Promise.resolve(promise);

Promise.resolve(theanable);

這三種形式都會(huì)產(chǎn)生一個(gè)新的Promise。其中:

第一種形式提供了自定義Promise的值的能力,它與Promise.reject(reason)對(duì)應(yīng)。兩者的不同,在于得到的Promise的狀態(tài)不同。

第二種形式,提供了創(chuàng)建一個(gè)Promise的副本的能力。

第三種形式,是將一個(gè)類似Promise的對(duì)象轉(zhuǎn)換成一個(gè)真正的Promise對(duì)象。它的一個(gè)重要作用是將一個(gè)其他實(shí)現(xiàn)的Promise對(duì)象封裝成一個(gè)當(dāng)前實(shí)現(xiàn)的Promise對(duì)象。例如你正在用bluebird,但是現(xiàn)在有一個(gè)Q的Promise,那么你可以通過此方法把Q的Promise變成一個(gè)bluebird的Promise。

實(shí)際上第二種形式可以歸在第三種形式中。

本節(jié)參考文章:ES6中的Promise.resolve()

推薦閱讀:性感的Promise...

7.偽類 / 偽元素 偽類
偽類 用于當(dāng)已有元素處于的某個(gè)狀態(tài)時(shí),為其添加對(duì)應(yīng)的樣式,這個(gè)狀態(tài)是根據(jù)用戶行為而動(dòng)態(tài)變化的。

當(dāng)用戶懸停在指定的元素時(shí),我們可以通過 :hover 來描述這個(gè)元素的狀態(tài)。雖然它和普通的 CSS 類相似,可以為已有的元素添加樣式,但是它只有處于 DOM 樹無法描述的狀態(tài)下才能為元素添加樣式,所以將其稱為偽類。

偽元素
偽元素 用于創(chuàng)建一些不在文檔樹中的元素,并為其添加樣式。

我們可以通過 :before 來在一個(gè)元素前增加一些文本,并為這些文本添加樣式。雖然用戶可以看到這些文本,但是這些文本實(shí)際上不在文檔樹中。

本節(jié)參考文章:前端面試題-偽類和偽元素、總結(jié)偽類與偽元素

8.DOMContentLoaded / load

DOM文檔加載的步驟為:

解析HTML結(jié)構(gòu)。

DOM樹構(gòu)建完成。//DOMContentLoaded

加載外部腳本和樣式表文件。

解析并執(zhí)行腳本代碼。

加載圖片等外部文件。

頁面加載完畢。//load

觸發(fā)的時(shí)機(jī)不一樣,先觸發(fā)DOMContentLoaded事件,后觸發(fā)load事件。

原生js

// 不兼容老的瀏覽器,兼容寫法見[jQuery中ready與load事件](http://www.imooc.com/code/3253),或用jQuery
document.addEventListener("DOMContentLoaded", function() {
   // ...代碼...
}, false);

window.addEventListener("load", function() {
    // ...代碼...
}, false);

jQuery

// DOMContentLoaded
$(document).ready(function() {
    // ...代碼...
});

//load
$(document).load(function() {
    // ...代碼...
});

head 中資源的加載

head 中 js 資源加載都會(huì)停止后面 DOM 的構(gòu)建,但是不影響后面資源的下載。

css資源不會(huì)阻礙后面 DOM 的構(gòu)建,但是會(huì)阻礙頁面的首次渲染。

body 中資源的加載

body 中 js 資源加載都會(huì)停止后面 DOM 的構(gòu)建,但是不影響后面資源的下載。

css 資源不會(huì)阻礙后面 DOM 的構(gòu)建,但是會(huì)阻礙頁面的首次渲染。

DomContentLoaded 事件的觸發(fā)
上面只是講了 html 文檔的加載與渲染,并沒有講 DOMContentLoaded 事件的觸發(fā)時(shí)機(jī)。直截了當(dāng)?shù)亟Y(jié)論是,DOMContentLoaded 事件在 html文檔加載完畢,并且 html 所引用的內(nèi)聯(lián) js、以及外鏈 js 的同步代碼都執(zhí)行完畢后觸發(fā)。
大家可以自己寫一下測(cè)試代碼,分別引用內(nèi)聯(lián) js 和外鏈 js 進(jìn)行測(cè)試。

load 事件的觸發(fā)
當(dāng)頁面 DOM 結(jié)構(gòu)中的 js、css、圖片,以及 js 異步加載的 js、css 、圖片都加載完成之后,才會(huì)觸發(fā) load 事件。

注意:
頁面中引用的js 代碼如果有異步加載的 js、css、圖片,是會(huì)影響 load 事件觸發(fā)的。video、audio、flash 不會(huì)影響 load 事件觸發(fā)。

推薦閱讀:再談 load 與 DOMContentLoaded
本節(jié)參考文章:DOMContentLoaded與load的區(qū)別、事件DOMContentLoaded和load的區(qū)別

9. 為什么將css放在頭部,將js文件放在尾部

因?yàn)闉g覽器生成Dom樹的時(shí)候是一行一行讀HTML代碼的,script標(biāo)簽放在最后面就不會(huì)影響前面的頁面的渲染。那么問題來了,既然Dom樹完全生成好后頁面才能渲染出來,瀏覽器又必須讀完全部HTML才能生成完整的Dom樹,script標(biāo)簽不放在body底部是不是也一樣,因?yàn)閐om樹的生成需要整個(gè)文檔解析完畢。

我們?cè)賮砜匆幌耤hrome在頁面渲染過程中的,綠色標(biāo)志線是First Paint的時(shí)間。納尼,為什么會(huì)出現(xiàn)firstpaint,頁面的paint不是在渲染樹生成之后嗎?其實(shí)現(xiàn)代瀏覽器為了更好的用戶體驗(yàn),渲染引擎將嘗試盡快在屏幕上顯示的內(nèi)容。它不會(huì)等到所有HTML解析之前開始構(gòu)建和布局渲染樹。部分的內(nèi)容將被解析并顯示。也就是說瀏覽器能夠渲染不完整的dom樹和cssom,盡快的減少白屏的時(shí)間。假如我們將js放在header,js將阻塞解析dom,dom的內(nèi)容會(huì)影響到First Paint,導(dǎo)致First Paint延后。所以說我們會(huì) 將js放在后面,以減少First Paint的時(shí)間,但是不會(huì)減少DOMContentLoaded被觸發(fā)的時(shí)間。

本節(jié)參考文章:DOMContentLoaded與load的區(qū)別

10.clientheight / offsetheight
clientheight:內(nèi)容的可視區(qū)域,不包含border。clientheight=padding+height-橫向滾動(dòng)軸高度。

這里寫圖片描述

offsetheight,它包含padding、border、橫向滾動(dòng)軸高度。 
offsetheight=padding+height+border+橫向滾動(dòng)軸高度

scrollheight,可滾動(dòng)高度,就是將滾動(dòng)框拉直,不再滾動(dòng)的高度,這個(gè)很好理解。 It includes the element’s padding, but not its border or margin.

本節(jié)參考文章:css clientheight、offsetheight、scrollheight詳解

11.use strict 有什么意義和好處

使調(diào)試更加容易。那些被忽略或默默失敗了的代碼錯(cuò)誤,會(huì)產(chǎn)生錯(cuò)誤或拋出異常,因此盡早提醒你代碼中的問題,你才能更快地指引到它們的源代碼。

防止意外的全局變量。如果沒有嚴(yán)格模式,將值分配給一個(gè)未聲明的變量會(huì)自動(dòng)創(chuàng)建該名稱的全局變量。這是JavaScript中最常見的錯(cuò)誤之一。在嚴(yán)格模式下,這樣做的話會(huì)拋出錯(cuò)誤。

消除 this 強(qiáng)制。如果沒有嚴(yán)格模式,引用null或未定義的值到 this 值會(huì)自動(dòng)強(qiáng)制到全局變量。這可能會(huì)導(dǎo)致許多令人頭痛的問題和讓人恨不得拔自己頭發(fā)的bug。在嚴(yán)格模式下,引用 null或未定義的 this 值會(huì)拋出錯(cuò)誤。

不允許重復(fù)的屬性名稱或參數(shù)值。當(dāng)檢測(cè)到對(duì)象中重復(fù)命名的屬性,例如:

var object = {foo: "bar", foo: "baz"};)

或檢測(cè)到函數(shù)中重復(fù)命名的參數(shù)時(shí),例如:

function foo(val1, val2, val1){})

嚴(yán)格模式會(huì)拋出錯(cuò)誤,因此捕捉幾乎可以肯定是代碼中的bug可以避免浪費(fèi)大量的跟蹤時(shí)間。

使 eval() 更安全。在嚴(yán)格模式和非嚴(yán)格模式下, eval() 的行為方式有所不同。最顯而易見的是,在嚴(yán)格模式下,變量和聲明在 eval() 語句內(nèi)部的函數(shù)不會(huì)在包含范圍內(nèi)創(chuàng)建(它們會(huì)在非嚴(yán)格模式下的包含范圍中被創(chuàng)建,這也是一個(gè)常見的問題源)。

在 delete 使用無效時(shí)拋出錯(cuò)誤。 delete 操作符(用于從對(duì)象中刪除屬性)不能用在對(duì)象不可配置的屬性上。當(dāng)試圖刪除一個(gè)不可配置的屬性時(shí),非嚴(yán)格代碼將默默地失敗,而嚴(yán)格模式將在這樣的情況下拋出異常。

本節(jié)參考文章:經(jīng)典面試題(4)

12.常見 JavaScript 內(nèi)存泄漏

意外的全局變量

JavaScript 處理未定義變量的方式比較寬松:未定義的變量會(huì)在全局對(duì)象創(chuàng)建一個(gè)新變量。在瀏覽器中,全局對(duì)象是 window 。

function foo(arg) {
    bar = "this is a hidden global variable";
}
真相是:

```
function foo(arg) {
    window.bar = "this is an explicit global variable";
}
```
函數(shù) foo 內(nèi)部忘記使用 var ,意外創(chuàng)建了一個(gè)全局變量。此例泄漏了一個(gè)簡(jiǎn)單的字符串,無傷大雅,但是有更糟的情況。

另一種意外的全局變量可能由 this 創(chuàng)建:

```
function foo() {
    this.variable = "potential accidental global";
}
// Foo 調(diào)用自己,this 指向了全局對(duì)象(window)
// 而不是 undefined
foo();
```
在 JavaScript 文件頭部加上 "use strict",可以避免此類錯(cuò)誤發(fā)生。啟用嚴(yán)格模式解析 JavaScript ,避免意外的全局變量。

被遺忘的計(jì)時(shí)器或回調(diào)函數(shù)
在 JavaScript 中使用 setInterval 非常平常。一段常見的代碼:

var someResource = getData();
setInterval(function() {
    var node = document.getElementById("Node");
    if(node) {
        // 處理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

此例說明了什么:與節(jié)點(diǎn)或數(shù)據(jù)關(guān)聯(lián)的計(jì)時(shí)器不再需要,node 對(duì)象可以刪除,整個(gè)回調(diào)函數(shù)也不需要了??墒牵?jì)時(shí)器回調(diào)函數(shù)仍然沒被回收(計(jì)時(shí)器停止才會(huì)被回收)。同時(shí),someResource 如果存儲(chǔ)了大量的數(shù)據(jù),也是無法被回收的。

對(duì)于觀察者的例子,一旦它們不再需要(或者關(guān)聯(lián)的對(duì)象變成不可達(dá)),明確地移除它們非常重要。老的 IE 6 是無法處理循環(huán)引用的。如今,即使沒有明確移除它們,一旦觀察者對(duì)象變成不可達(dá),大部分瀏覽器是可以回收觀察者處理函數(shù)的。

觀察者代碼示例:

var element = document.getElementById("button");
function onClick(event) {
    element.innerHTML = "text";
}
element.addEventListener("click", onClick);

對(duì)象觀察者和循環(huán)引用注意事項(xiàng)

老版本的 IE 是無法檢測(cè) DOM 節(jié)點(diǎn)與 JavaScript 代碼之間的循環(huán)引用,會(huì)導(dǎo)致內(nèi)存泄漏。如今,現(xiàn)代的瀏覽器(包括 IE 和 Microsoft Edge)使用了更先進(jìn)的垃圾回收算法,已經(jīng)可以正確檢測(cè)和處理循環(huán)引用了。換言之,回收節(jié)點(diǎn)內(nèi)存時(shí),不必非要調(diào)用 removeEventListener 了。

脫離 DOM 的引用
有時(shí),保存 DOM 節(jié)點(diǎn)內(nèi)部數(shù)據(jù)結(jié)構(gòu)很有用。假如你想快速更新表格的幾行內(nèi)容,把每一行 DOM 存成字典(JSON 鍵值對(duì))或者數(shù)組很有意義。此時(shí),同樣的 DOM 元素存在兩個(gè)引用:一個(gè)在 DOM 樹中,另一個(gè)在字典中。將來你決定刪除這些行時(shí),需要把兩個(gè)引用都清除。

var elements = {
    button: document.getElementById("button"),
    image: document.getElementById("image"),
    text: document.getElementById("text")
};
function doStuff() {
    image.src = "http://some.url/image";
    button.click();
    console.log(text.innerHTML);
    // 更多邏輯
}
function removeButton() {
    // 按鈕是 body 的后代元素
    document.body.removeChild(document.getElementById("button"));
    // 此時(shí),仍舊存在一個(gè)全局的 #button 的引用
    // elements 字典。button 元素仍舊在內(nèi)存中,不能被 GC 回收。
}

此外還要考慮 DOM 樹內(nèi)部或子節(jié)點(diǎn)的引用問題。假如你的 JavaScript 代碼中保存了表格某一個(gè) 的引用。將來決定刪除整個(gè)表格的時(shí)候,直覺認(rèn)為 GC 會(huì)回收除了已保存的 以外的其它節(jié)點(diǎn)。實(shí)際情況并非如此:此 是表格的子節(jié)點(diǎn),子元素與父元素是引用關(guān)系。由于代碼保留了 的引用,導(dǎo)致整個(gè)表格仍待在內(nèi)存中。保存 DOM 元素引用的時(shí)候,要小心謹(jǐn)慎。

閉包

閉包是 JavaScript 開發(fā)的一個(gè)關(guān)鍵方面:匿名函數(shù)可以訪問父級(jí)作用域的變量。

避免濫用

本節(jié)參考文章:4類 JavaScript 內(nèi)存泄漏及如何避免

13.引用計(jì)數(shù) / 標(biāo)記清除

js垃圾回收有兩種常見的算法:引用計(jì)數(shù)和標(biāo)記清除。

引用計(jì)數(shù)就是跟蹤對(duì)象被引用的次數(shù),當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)為0即沒有其他對(duì)象引用它時(shí),說明該對(duì)象已經(jīng)無需訪問了,因此就會(huì)回收其所占的內(nèi)存,這樣,當(dāng)垃圾回收器下次運(yùn)行就會(huì)釋放引用數(shù)為0的對(duì)象所占用的內(nèi)存。

標(biāo)記清除法是現(xiàn)代瀏覽器常用的一種垃圾收集方式,當(dāng)變量進(jìn)入環(huán)境(即在一個(gè)函數(shù)中聲明一個(gè)變量)時(shí),就將此變量標(biāo)記為“進(jìn)入環(huán)境”,進(jìn)入環(huán)境的變量是不能被釋放,因?yàn)橹挥袌?zhí)行流進(jìn)入相應(yīng)的環(huán)境,就可能會(huì)引用它們。而當(dāng)變量離開環(huán)境時(shí),就標(biāo)記為“離開環(huán)境”。

垃圾收集器在運(yùn)行時(shí)會(huì)給儲(chǔ)存在內(nèi)存中的所有變量加上標(biāo)記,然后會(huì)去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標(biāo)記,當(dāng)執(zhí)行完畢那些沒有存在引用 無法訪問的變量就被加上標(biāo)記,最后垃圾收集器完成清除工作,釋放掉那些打上標(biāo)記的變量所占的內(nèi)存。

 function problem() {
    var A = {};
    var B = {};
    A.a = B;
    B.a = A;
}
引用計(jì)數(shù)存在一個(gè)弊端就是循環(huán)引用問題(上邊)
標(biāo)記清除不存在循環(huán)引用的問題,是因?yàn)楫?dāng)函數(shù)執(zhí)行完畢之后,對(duì)象A和B就已經(jīng)離開了所在的作用域,此時(shí)兩個(gè)變量被標(biāo)記為“離開環(huán)境”,等待被垃圾收集器回收,最后釋放其內(nèi)存。

分析以下代碼:

    function createPerson(name){
        var localPerson = new Object();
        localPerson.name = name;
        return localPerson;
    }
    var globalPerson = createPerson("Junga");
    globalPerson = null;//手動(dòng)解除全局變量的引用

在這個(gè)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/100981.html

相關(guān)文章

  • 前端本功-常見概念(一)

    摘要:前端基本功常見概念一點(diǎn)這里前端基本功常見概念二點(diǎn)這里前端基本功常見概念三點(diǎn)這里什么是原型鏈當(dāng)一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法時(shí)候就會(huì)產(chǎn)生一個(gè)原型鏈。函數(shù)式編程是聲明式而不是命令式,并且應(yīng)用程序狀態(tài)通過純函數(shù)流轉(zhuǎn)。 前端基本功-常見概念(一) 點(diǎn)這里前端基本功-常見概念(二) 點(diǎn)這里前端基本功-常見概念(三) 點(diǎn)這里 1.什么是原型鏈 當(dāng)一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方...

    bladefury 評(píng)論0 收藏0
  • 前端本功-常見概念()

    摘要:前端基本功常見概念一點(diǎn)這里前端基本功常見概念二點(diǎn)這里前端基本功常見概念三點(diǎn)這里超文本標(biāo)記語言,顯示信息,不區(qū)分大小寫升級(jí)版的,區(qū)分大小寫可擴(kuò)展標(biāo)記語言被用來傳輸和存儲(chǔ)數(shù)據(jù)規(guī)范采用異步方式加載模塊,模塊的加載不影響它后面語句的運(yùn)行。 前端基本功-常見概念(一) 點(diǎn)這里前端基本功-常見概念(二) 點(diǎn)這里前端基本功-常見概念(三) 點(diǎn)這里 1.HTML / XML / XHTML html...

    happen 評(píng)論0 收藏0
  • 前端2018現(xiàn)在上車還還得及么

    摘要:面向?qū)ο笕筇卣骼^承性多態(tài)性封裝性接口。第五階段封裝一個(gè)屬于自己的框架框架封裝基礎(chǔ)事件流冒泡捕獲事件對(duì)象事件框架選擇框架。核心模塊和對(duì)象全局對(duì)象,,,事件驅(qū)動(dòng),事件發(fā)射器加密解密,路徑操作,序列化和反序列化文件流操作服務(wù)端與客戶端。 第一階段: HTML+CSS:HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開發(fā)、 JavaScript基礎(chǔ):Js基礎(chǔ)教程、js內(nèi)置對(duì)...

    stormgens 評(píng)論0 收藏0
  • 前端2018現(xiàn)在上車還還得及么

    摘要:面向?qū)ο笕筇卣骼^承性多態(tài)性封裝性接口。第五階段封裝一個(gè)屬于自己的框架框架封裝基礎(chǔ)事件流冒泡捕獲事件對(duì)象事件框架選擇框架。核心模塊和對(duì)象全局對(duì)象,,,事件驅(qū)動(dòng),事件發(fā)射器加密解密,路徑操作,序列化和反序列化文件流操作服務(wù)端與客戶端。 第一階段: HTML+CSS:HTML進(jìn)階、CSS進(jìn)階、div+css布局、HTML+css整站開發(fā)、 JavaScript基礎(chǔ):Js基礎(chǔ)教程、js內(nèi)置對(duì)...

    mylxsw 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<