JavaScript忍者秘籍

函數(shù)調(diào)用

構(gòu)造器

構(gòu)造器(constructor)被調(diào)用時(shí)候會(huì)發(fā)生:

  1. 創(chuàng)建一個(gè)新對(duì)象
  2. 傳遞給構(gòu)造器的對(duì)象是this參數(shù)又沾,從而成為構(gòu)造器的函數(shù)上下文
  3. 如果沒有顯式的返回值衍锚,新創(chuàng)建的對(duì)象則作為構(gòu)造器的返回值進(jìn)行返回
var a = new B();
// 相當(dāng)于
// 1. 創(chuàng)建一個(gè)新對(duì)象
var obj = {};
// 2. 指定__proto__屬性
obj.__proto__ = B.prototype;
// 3. 指定構(gòu)造函數(shù)
obj.constructor = B;
// 4. this指針更正
B.call(obj);
// 5. 返回新創(chuàng)建的對(duì)象
return obj;

this的指向問題

函數(shù)調(diào)用方式之間的主要差異是:作為this參數(shù)傳遞給執(zhí)行函數(shù)的上下文對(duì)象之間的區(qū)別:

  1. 作為方法調(diào)用诫舅,this即上下文對(duì)象指向方法的擁有者
var a = {
    getname(){}
}
a.getname();
  1. 作為全局對(duì)象進(jìn)行調(diào)用河爹,this指向window。
  2. 作為構(gòu)造器進(jìn)行調(diào)用衙解,this指向新創(chuàng)建的對(duì)象實(shí)例。
  3. 被apply()和call()調(diào)用的時(shí)候令野,this會(huì)被apply和call指定到調(diào)用者上舀患。也就是指定上下文
    重寫個(gè)forEach案例
function forEach(list,callback){
    for(var i=0;i<list.length;i++){
        // 將當(dāng)前元素作為第一個(gè)參數(shù)傳入,當(dāng)前索引作為第二個(gè)參數(shù)傳入
        // 這就使得當(dāng)前元素變成函數(shù)的上下文
        callback.call(this,list[i],i);
    };
}
var arr = [1,2,3,4,5];
forEach(arr,function(item,index){
    console.log(item,index);
})

揮舞函數(shù)

遞歸

檢查字符串是否為回文

function fn(text){
    if(text.length<=1) return true;
    if(text.charAt(0) != text.charAt(text.length-1)) return false;
    return arguments.callee(text.substr(1,text.length-2))
}
var str = "1234567654321";
fn(str);
// 13個(gè)字符執(zhí)行7次气破,沒任何性能問題

Tips:“!!”兩個(gè)感嘆號(hào)可以將任意JS表達(dá)式轉(zhuǎn)化為其等效布爾值的簡單方法聊浅。

!!"he shot me down" === true
!!0 === false;

重載

利用apply和call查找數(shù)組中的最小值和最大值

function small(arr){
    return Math.min.apply(Math,arr);
}
function largest(arr){
    return Math.max.apply(Math,arr);
}
var arr = [1,2,23,4,5,6,7,78];
small(arr);
// 上述其實(shí)就等價(jià)于Math.min(1,2,23,4,5,6,7,78)

使用apply將arr的上下文指定給Math函數(shù)
重載其實(shí)就是讓參數(shù)變的更多,比如多參數(shù)實(shí)現(xiàn)一個(gè)參數(shù)就實(shí)現(xiàn)

函數(shù)的length屬性
申明函數(shù)都會(huì)有一個(gè)name和length屬性现使,此處的length屬性和arguments的length一樣低匙。
fn的length表示函數(shù)代碼寫法上接收到的參數(shù),arguments表示函數(shù)實(shí)際調(diào)用中接收到的參數(shù)碳锈。

function fn(a,b,c,d,e){
    console.log(arguments.length);  // 2
}
fn(1,2);
console.log(fn.length); // 5

判斷函數(shù)的length可以方便的去給函數(shù)定義重載顽冶,比如:

function fn(){
    switch(arguments.length){
        case 0:
            // do soemthing...
            break;
        default:
            break;
    }
}

閉包

書上的概念是:
閉包是一個(gè)函數(shù)在創(chuàng)建時(shí)
允許該自身函數(shù)訪問并操作該自身函數(shù)之外的變量時(shí)
所創(chuàng)建的作用域。

var outerVal = "ninja";
var later;
function outerFunction(){
    var innerVal = "samurai";
    function innerFunction(param){
        console.log(outerVal);
        console.log(innerVal);
        console.log(param);
        console.log(tooLate);
    }
    later = innerFunction;
    // later被賦值的那一刻售碳,innerFunction的作用域也被賦值給了later强重,所以最后later是能訪問所有作用域下的變量
}
var tooLate = "I ma tooLate";
outerFunction();
later('aaa');

在innerFunction賦值給later的時(shí)候,不僅聲明了一個(gè)函數(shù)贸人,還創(chuàng)建了一個(gè)閉包间景,該閉包不僅包含函數(shù)申明,還包含了函數(shù)聲明的那一時(shí)刻點(diǎn)上該作用域中的所有變量艺智。
像保護(hù)氣泡一樣拱燃,只要innerFunction()函數(shù)一直存在,它的閉包就保持該作用域中即將被垃圾回收的變量力惯。

閉包在計(jì)時(shí)器(timer)和回調(diào)(callback)中的作用

function animateIt(el){
    var elem = document.getElementById(el);
    var tick = 0;
    var timer = setInterval(function(){
        if(tick<100){
            elem.style.left = elem.style.top = tick + "px";
        }else{
            clearInterval(timer);
            console.log(tick);
            console.log(timer);
            console.log(elem);
        }
    },10)
}
animateIt('box');

上述代碼中創(chuàng)建的每一個(gè)計(jì)時(shí)器setInterval都可以看成是一個(gè)保護(hù)泡。每個(gè)動(dòng)畫都有自己的“私有”氣泡召嘶。

閉包不是在創(chuàng)建那一時(shí)刻點(diǎn)的狀態(tài)的快照父晶,而是當(dāng)時(shí)一個(gè)真實(shí)狀態(tài)的封裝,連通作用域的一起的封裝弄跌。

綁定函數(shù)上下文

// <button id="test">click me</button>
var button = {
    clicked:false,
    click(){
        this.clicked = true;
        console.log(button.clicked);    // false
        console.log(this.clicked);      // true
        console.log(this);              // <button id="test">click me</button>
    }
}
var elem = document.getElementById('test');
elem.addEventListener('click',button.click,false);

上述代碼在執(zhí)行button.click的時(shí)候就this的作用域指向的是當(dāng)前點(diǎn)擊的button甲喝。所以輸出this.clicked的時(shí)候是true。而輸出button.clicked的時(shí)候是false铛只,因?yàn)閠his的指向問題埠胖。也就是函數(shù)的上下文環(huán)境已經(jīng)變化了。

這種時(shí)候使用apply或者call強(qiáng)制綁定作用域就可以解決:

function bind(context,name){
    return function(){
        return context[name].apply(context,arguments);
    }
}
var button = {
    clicked:false,
    click(){
        this.clicked = true;
        console.log(button.clicked);    // true
        console.log(this.clicked);      // true
        console.log(this);              // 當(dāng)前button對(duì)象
    }
}
var elem = document.getElementById('test');
elem.addEventListener('click',bind(button,"click"),false);
// 強(qiáng)制將click事件的作用域指向到button對(duì)象上

函數(shù)柯里化

假設(shè)想要將一個(gè)字符串分隔成CSV(逗號(hào)分隔)淳玩,并忽略多余的空格直撤。通過curry實(shí)現(xiàn):

// 給function上定義一個(gè)原型方法
Function.prototype.curry = function(){
    var fn = this,args = Array.prototype.slice.call(arguments);
    return function(){
        var arg = 0;
        for(var i=0;args.length && arg < arguments.length;i++){
            if(args[i] === undefined){
                args[i] = arguments[arg++];
            }
        }
        return fn.apply(this,args);
    }
}

其實(shí)就是將函數(shù)中的agrguments收集起來組成一個(gè)數(shù)組然后再操作。

即時(shí)函數(shù)(自執(zhí)行函數(shù))

充分利用閉包的典范蜕着。

(function(){
     //...
})()

原型和面向?qū)ο?/h1>

實(shí)例屬性

prototype
使用new操作符將函數(shù)作為構(gòu)造器進(jìn)行調(diào)用的時(shí)候谋竖,其上下文被定義為新對(duì)象實(shí)例红柱。

function Ninja(){
    this.swung = false;
    this.swingSword = function(){           // 優(yōu)先級(jí)高
        console.log(1);                     // 輸出1
        return !this.swung;
    }
}
Ninja.prototype.swingSword = function(){    // 優(yōu)先級(jí)低
    console.log(2);                         // 不輸出任何值
    return this.swung;
}
var n = new Ninja();
console.log(n.swingSword());                // true

這里在訪問swingSword()的時(shí)候先已經(jīng)在Ninja中找到對(duì)應(yīng)方法,如果沒有找到才會(huì)去prototype上查找蓖乘。
在構(gòu)造器內(nèi)的綁定操作優(yōu)先級(jí)永遠(yuǎn)都高于在原型上綁定操作的優(yōu)先級(jí)锤悄。
將上述代碼修改一下:

function Ninja(){
    this.swung = false;
}
var n = new Ninja();
Ninja.prototype.swingSword = function(){
    return this.swung;
}
console.log(n.swingSword());  // false

上述代碼的過程:

  1. 在引用對(duì)象的一個(gè)屬性時(shí),首先檢查該對(duì)象本身是否擁有該屬性嘉抒,如果有零聚,則直接返回。
  2. 如果沒有就查找該對(duì)象的prototype上是否有該屬性些侍,如果有隶症,則返回,
  3. 如果該對(duì)象上的prototype也沒有就在其父級(jí)(有的話)上的prototype上查找娩梨。
  4. 查找到了返回沿腰,沒有查找到,就返回undefined狈定。
    上述這么個(gè)尋找的過程就是原型鏈颂龙。

constructor
JS中的每一個(gè)對(duì)象,都有一個(gè)名為constructor的隱式屬性纽什,該屬性引用的是創(chuàng)建該對(duì)象的構(gòu)造器措嵌。由于prototype是構(gòu)造器的一個(gè)屬性,所以每一個(gè)對(duì)象都有一種方式可以找到自己的原型芦缰。

function Ninja(){}
var ninja = new Ninja();
console.log(ninja.constructor);     // ? Ninja(){}

constructor指向其本身的構(gòu)造器企巢。

使用構(gòu)造器進(jìn)行對(duì)象類型判斷

function Ninja(){}
var ninja = new Ninja();
console.log(typeof ninja == 'object');      // true
console.log(ninja instanceof Ninja);        // true
console.log(ninja.constructor == Ninja);    // true

使用constructor重新創(chuàng)建一個(gè)實(shí)例

function Ninja(){}
var ninja = new Ninja();
var ninja2 = new ninja.constructor();
console.log(ninja2 instanceof Ninja);       // true
console.log(ninja2 !== ninja);              // true

上述實(shí)現(xiàn)了新實(shí)例的創(chuàng)建,算是深拷貝让蕾。

繼承和原型鏈

創(chuàng)建原型鏈最好的方式是浪规,使用一個(gè)對(duì)象的實(shí)例作為另外一個(gè)對(duì)象的原型。

SubClass.prototype = new SuperClass();
// 比如
var Person = function(){
    this.age = 19;
    this.name = "zhangsan"
}
function Tom(){};
Tom.prototype = new Person();
var ethan = new Tom();
console.log(ethan);   // Tom {},查找__proto__上有兩個(gè)屬性探孝,age和name

這樣Tom的原型上就繼承了來自Person所有的共享的屬性和方法笋婿。
既然這樣可以為啥不能直接原型等于原型呢?

Tom.prototype = Person.prototype;

這樣做就是一個(gè)淺拷貝顿颅,Person.prototype上的屬性和方法變更的話就會(huì)影響到Tom缸濒,影響很大。

擴(kuò)展對(duì)象

有時(shí)候看別人的代碼會(huì)直接在對(duì)象或者數(shù)組的prototype原型上直接添加一個(gè)擴(kuò)展方法:

Object.prototype.keys = function(){
    var keys = [];
    for(var p in this){
        console.log(this);      // {a:1,b:2,c:3}
        console.log(p);         // a,b,c,keys
        keys.push(p);
    }
    return keys;
}
console.log({a:1,b:2,c:3}.keys());  // [a,b,c,keys]4個(gè)字符串組成的數(shù)組

這種問題很難預(yù)防粱腻,這樣操作會(huì)造成隱患庇配。但是上述代碼可以通過hasOwnProperty方法來解決。

Object.prototype.keys = function(){
    var keys = [];
    for(var p in this){
        if(this.hasOwnProperty(p)) keys.push(p);
    }
    return keys;
}
console.log({a:1,b:2,c:3}.keys());

hasOwnProperty是用來檢查一個(gè)屬性是對(duì)象實(shí)例上定義的還是從原型里導(dǎo)入的绍些。
上述代碼中的a,b,c都是在實(shí)例上定義的捞慌,keys方法是從原型中導(dǎo)入的。

原生對(duì)象的子類化

function MyArray(){}
MyArray.prototype.length = 0;
(function(){
    var methods = ["push","pop","shift","unshift","slice","splice","join"];
    for(var i=0;i<methods.length;i++)(function(name){
        MyArray.prototype[name] = function(){
            return Array.prototypep[name].apply(this,arguments);
        }
    })(methods[i])
})()

var mine = new MyArray();
mine.push(1,2,3);
console.log(mine);

實(shí)例化問題

普通函數(shù)和構(gòu)造函數(shù)引用不確定的時(shí)候會(huì)造成的一些問題
污染當(dāng)前作用域柬批,通常是全局命名空間

function User(f,l){
    this.name = f+l;
}
var name = "aa";
var user = User("bb","cc");
console.log(name);      // name輸出bbcc卿闹,而不是aa

User被執(zhí)行時(shí)候設(shè)置了name的屬性揭糕,而被調(diào)用時(shí)候的作用域是全局的。這些都是編碼隱患锻霎,所以let和const的出現(xiàn)能有一些幫助著角。
這也體現(xiàn)了js的這種弱語言的特點(diǎn)。
那這種本該使用new操作符實(shí)例化的構(gòu)造函數(shù)旋恼,缺被當(dāng)做普通函數(shù)引用了的問題怎么避免呢吏口?
使用instanceof來檢測

function User(f,l){
    if(!(this instanceof arguments.callee)){
        return new User(f,l);
    }
    this.name = f+l;
}
var name = "aa";
var user = User("bb","cc");
console.log(name);      // aa

this instanceof arguments.callee 的結(jié)果為true時(shí)表示其是被new操作符實(shí)例化調(diào)用構(gòu)造函數(shù)的。
為false表示只是普通函數(shù)的引用冰更。

正則表達(dá)式

正則表達(dá)式申明

有兩種方法:

  1. 正則字面量
var pattern = /test/;
  1. RegExp實(shí)例
var pattern = new RegExp("test");

除了表達(dá)式本身产徊,還有三個(gè)標(biāo)志可以與正則表達(dá)式進(jìn)行關(guān)聯(lián)。

  • i 讓正則表達(dá)式不區(qū)分大小寫蜀细,所有/test/i不僅可以匹配"test"舟铜,還可以匹配"Test","TEST"等
  • g 匹配模式中的所有實(shí)例奠衔,而不是默認(rèn)只匹配第一次出現(xiàn)的結(jié)果谆刨。
  • m 允許匹配多行,比如可以匹配文本區(qū)元素testarea中的值

精確匹配
/test/表示test必須連在一起被匹配

匹配一類字符
[abc]表示只需要匹配到a,b,c中任意一個(gè)字符
[^abc]表示需要匹配到 a,b,c之外的所有字符
[a-m]表示需要匹配到從字母a到m的所有字符归斤,包括a和m痊夭。

轉(zhuǎn)義
對(duì)特殊的字符需要進(jìn)行轉(zhuǎn)義
比如需要匹配“[^]”等特殊字符的時(shí)候就需要先將它們轉(zhuǎn)義。 /\[\^]/用這種方式去匹配特殊字符脏里。另外"\"是用于匹配反斜杠""的她我,也是正常的規(guī)則。

匹配開始和匹配結(jié)束
/^test/表示字符串必須以test開頭
/test/表示字符串必須以test結(jié)尾 /^test/表示整個(gè)字符串只能是test

重復(fù)出現(xiàn)
/t?est/ 匹配“test”和“est”迫横,?表示前面的字符可以出現(xiàn)一次或根本不出現(xiàn)
/t+est/ 匹配“ttest,tttest,ttttttest”等番舆,但是不匹配“est”, + 表示一個(gè)字符出現(xiàn)一次或者多次
/a{4}/ 匹配連續(xù)出現(xiàn)aaaa的字符串
/a{4,10}/ 匹配任何含有“aaaa”到“aaaaaaaaaaa”,也就是又4或者10位a組成的連續(xù)字符串
/a{4,}/ 匹配4個(gè)或多于4個(gè)“a”組成的連續(xù)字符串
正則中的重復(fù)操作都是貪婪的矾踱,比如對(duì)“aaa”進(jìn)行字符串匹配合蔽,/a+/將匹配所有這三個(gè)字符,而/a+?/表示只匹配一個(gè)a字符即可介返。所以平時(shí)的寫法要注意一些性能優(yōu)化。

預(yù)定義字符類
這個(gè)是用來檢測一些鍵盤空格等操作符沃斤。舉幾個(gè)常見例子

預(yù)定義術(shù)語 匹配內(nèi)容
\r 回車
\n 換行
\d 任意數(shù)字圣蝎,等價(jià)于[0-9]
\D 任意非數(shù)字,等價(jià)于[^0-9]
\w 匹配包括下劃線的任意單詞字符衡瓶,等價(jià)于[A-Za-z0-9_]
\W 匹配任何非單詞字符徘公,等價(jià)于[^A-Za-z0-9]
\s 匹配任何空白字符,包括空格哮针、制表符关面、換頁符
\S 匹配任何非空白字符
\b 匹配單詞邊界
\B 匹配非單詞邊界

特殊字符匹配

特別字符 描述
$ 匹配輸入字符串的結(jié)尾位置
() 匹配一個(gè)子表達(dá)式的開始和結(jié)束位置坦袍。
* 匹配零次或多次。
+ 匹配一次或者多次
. 匹配除換行符\n之外的任何單字符
[ 標(biāo)記一個(gè)中括號(hào)表達(dá)式的開始
? 匹配零次或一次等太,或指明一個(gè)非貪婪限定符
\ 匹配特殊字符捂齐。\ 表示匹配自身
^ 匹配字符串的開始位置,但是如果在[]方括號(hào)中使用缩抡,表示不接受該字符集合
{} 標(biāo)記限定符表達(dá)式的開始
` `

或操作符(OR)
就是"|"表示或的關(guān)系奠宜。
/a|b/ 表示匹配字符a或者b
/(ab)+|(cd)+/ 表示匹配多次出現(xiàn)ab或多次出現(xiàn)cd字符串

編譯正則表達(dá)式

正則表達(dá)式是一個(gè)多階段的處理過程。其有兩個(gè)重要階段就是 編譯執(zhí)行瞻想。

<div class="samurai ninja"></div>
<div class="ninja samurai"></div>
<div></div>
<span class="samurai ninja ronin"></span>
<script>
function findClassInElements(className,type){
    var elems = document.getElementsByTagName(type ||'*');
    var regex = new RegExp("(^|\\s)" + className + "(\\s|$)");
    var results = [];
    for(var i=0;i<elems.length;i++){
        if(regex.test(elems[i].className)){
            results.push(elems[i]);
        }
    }
    return results;
}
console.log(findClassInElements("ninja","div").length);
console.log(findClassInElements("ninja","span").length);
</script>

用全局表達(dá)式進(jìn)行匹配

var html = '<div class="test"><b>Hello</b><i>world!</i></div>';
var res = html.match(/<(\/?)(\w+)([^>]*?)>/);
var all = html.match(/<(\/?)(\w+)([^>]*?)>/g);
console.log(res,all);

匹配解析:
/<>/ 匹配"<>"
/< (/?) >/ 匹配是否存在"/"压真,檢測</>這種的存在
/< (\w+) >/ 匹配中間div的名稱,\w等價(jià)于[A-Za-z0-9_]蘑险,\w+表示字符串是多個(gè)的存在的
/< ([^>]*?) >/ 匹配非>字符串滴肿,?表示前面非>字符有可能存在有可能不存在

使用exec

var html = '<div class="test"><b>Hello</b><i>world!</i></div>';
var tag = /<(\/?)(\w+)([^>]*?)>/g,match;
var num = 0;
while((match = tag.exec(html)) !== null){
    console.log(match[0]);
}

match和exec的用法不同:

var html = '<div class="test"><b>Hello</b><i>world!</i></div>';
var tag = /<(\/?)(\w+)([^>]*?)>/g;
var res = html.match(tag);
var res2 = tag.exec(html);

上述兩者返回的結(jié)果相同。

replace中嵌入正則

將css樣式寫法由-改寫成駝峰式佃迄,比如:border-bottom-width改成borderBottomWidth

var cls = "border-bottom-width";
var reg = /-(\w)/g; // 匹配“-”開頭后面一個(gè)是[A-Za-z0-9_]的字符格式
var res = cls.replace(reg,function(all,letter){
    return letter.toUpperCase();
})
console.log(res);

將url字符串“foo=1&foo=2&foo=3&blash=4&foo=5”替換成“foo=1,2,3,5&blash=4”

var str = "foo=1&foo=2&foo=3&blash=4&foo=5";
var reg = /([^=&]+)=([^&]*)/g;
function compress(source){
    var keys = {},newStr="";
    source.replace(reg,function(full,key,value){
        if(!keys[key]){
            keys[key] = value;
        }else{
            keys[key] = [].concat(keys[key],value);
        }
    })
    for(var i in keys){
        if(Array.isArray(keys[i])){
            newStr += (i+'='+keys[i].join(',')+'&');
        }else{
            newStr += (i+'='+keys[i] + '&');
        }
    }
    return newStr.substring(0,newStr.length-1);
}
var newStr = compress(str);
console.log(newStr);

正則分析:/([^=&]+)=([^&]*)/g
/()=()/ 匹配所有的a=b的格式
/([^=&]+)=()/ 表示a部分包含"="和"&"特殊字符
/()=([^&]*)/ 表示不包含"&"特殊字符泼差,不管是出現(xiàn)零次還是多次
其實(shí)上述代碼完全可以寫成:/([^=&])=([^=&])/

一些常見的正則引用

實(shí)現(xiàn)string.trim函數(shù)

function trim(str){
    var reg = /^\s+|\s+$/g;
    return (str || '').replace(reg,"");
}
console.log(trim("   dwada  dwad  dwa  "));

正則解析
/^\s+/ 這里"^"不是在[]中使用的,所以其是匹配第一個(gè)字符和屎。\s表示匹配空格拴驮,\s+表示不止一個(gè)空格
/\s+/表示結(jié)尾
/^\s+|\s+/g 合起來的意思就是匹配所有的開始位置和結(jié)束位置都是空格且不知道一個(gè)空格的字符串,找到然后使用replace替換成功“”柴信。這樣就去除了收尾的空格套啤。 如果去除收尾的"^",就表示將字符串中所有的空格都去掉随常。

匹配換行符

var html = "<div>Hello</div>\n<i>world!</i>";
var reg1 = /.*/;
var reg2 = /[\S\s]*/;
var reg3 = /(?:.|\s)*/;
console.log(reg1.exec(html)[0]);
console.log(reg2.exec(html)[0]);
console.log(reg3.exec(html)[0]);

正則分析:
/./ .表示匹配除換行符以外的所有字符潜沦,表示有另個(gè)或多個(gè)
/[\S\s]/ 表示任何非空字符和任何空白字符。這個(gè)效率最佳
/(?:.|/s)*/ 沒看懂绪氛。唆鸡。。

線程和定時(shí)器

代碼求值機(jī)制

eval()

函數(shù)構(gòu)造器

var add = new Function('a','b','return a+b');
console.log(add(3,4));

理解DOM特性和DOM屬性

特性(attribute)是DOM構(gòu)建的一個(gè)組成部分枣察。
屬性(property)是元素保持運(yùn)行時(shí)信息的主要手段争占。

通過DOM方法和屬性訪問特性值

window.onload = function(){
    var div = document.getElementsByTagName("div")[0];
    div.setAttribute("id","div1");
    div.id ="div2";
    div.setAttribute("id","div3");
}

不老事件

綁定和解綁事件處理程序

在DOM2下,一般使用addEventListenerremoveEventListener事件來綁定和解綁事件序目。IE9以前的版本使用的是attachEvent()detachEvent()
大多數(shù)情況下臂痕,兩種情況很類似,只有一個(gè)明顯的例外:IE Model沒有提供事件捕獲階段的監(jiān)聽方式猿涨,其只支持事件處理過程的冒泡階段握童。
在冒泡階段,事件將事件源傳播到DOM根節(jié)點(diǎn)叛赚,而在捕獲階段澡绩,則是從DOM根節(jié)點(diǎn)遍歷傳播到事件源上稽揭。

文檔就緒事件

document.ready 在文檔樹加載完畢之后就會(huì)執(zhí)行
window.onload 在所有文檔加載完成(包括圖片等素材元素加載)之后再執(zhí)行
下面是一個(gè)實(shí)現(xiàn)跨瀏覽器都兼容的DOM Ready監(jiān)聽事件

(function(){
    var isReady = false,contentLoadedHandler;
    function ready(){
        if(!isReady){
            triggerEvent(document, "ready");
            isReady = true;
        }
    }

    if(document.readyState === "complete"){
        ready();
    }
    // 對(duì)于w3c瀏覽器,創(chuàng)建一個(gè)DOMContentLoaded事件處理程序肥卡,觸發(fā)ready處理程序溪掀,然后再刪除自身
    if(document.addEventListener){
        contentLoadedHandler = function(){
            document.removeEventListener("DOMContentLoaded",contentLoadedHandler,false);
            ready();
        }
        document.addEventListener("DOMContentLoaded",contentLoadedHandler,false);
    }else if(document.attachEvent){
        contentLoadedHandler = function(){
            // IE內(nèi)核通過判斷document.readyState屬性判斷DOM已經(jīng)加載完畢
            if(document.readyState === "complete"){
                document.attachEvent("onreadystatechange",contentLoadedHandler);
                ready();
            }
        }
        document.attachEvent("onreadystatechange",contentLoadedHandler);

        var toplevel = false;
        try{
            toplevel = window.frameElement == null;
        }catch(e){}

        if(document.documentElement.doScroll && toplevel){
            doScrollCheck();
        }
        function doScrollCheck(){
            if(isReady) return;
            try{
                document.documentElement.doScroll("left");
            }catch(error){
                setTimeout(doScrollCheck,1);
                return;
            }
            ready();
        }
    }
})()

總結(jié)

說實(shí)話,這本書是跳著看的~~~
中間精華部分還是正則表達(dá)式部分召调。
個(gè)人覺得介紹JS基礎(chǔ)的好好的去啃(舔來舔去膨桥,當(dāng)一個(gè)添狗)幾本圣經(jīng)是最好的方式。其他的書籍選擇性的去看唠叛,這樣會(huì)有其他角度的理解只嚣。
PS:感覺翻譯的不太好。一周讀完

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艺沼,一起剝皮案震驚了整個(gè)濱河市册舞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌障般,老刑警劉巖调鲸,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挽荡,居然都是意外死亡藐石,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門定拟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來于微,“玉大人,你說我怎么就攤上這事青自≈暌溃” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵延窜,是天一觀的道長恋腕。 經(jīng)常有香客問我,道長逆瑞,這世上最難降的妖魔是什么荠藤? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮获高,結(jié)果婚禮上哈肖,老公的妹妹穿的比我還像新娘。我一直安慰自己谋减,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布扫沼。 她就那樣靜靜地躺著出爹,像睡著了一般庄吼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上严就,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天总寻,我揣著相機(jī)與錄音,去河邊找鬼梢为。 笑死渐行,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的铸董。 我是一名探鬼主播祟印,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粟害!你這毒婦竟也來了蕴忆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤悲幅,失蹤者是張志新(化名)和其女友劉穎套鹅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汰具,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡卓鹿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了留荔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吟孙。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖存谎,靈堂內(nèi)的尸體忽然破棺而出拔疚,到底是詐尸還是另有隱情,我是刑警寧澤既荚,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布稚失,位于F島的核電站,受9級(jí)特大地震影響恰聘,放射性物質(zhì)發(fā)生泄漏句各。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一晴叨、第九天 我趴在偏房一處隱蔽的房頂上張望凿宾。 院中可真熱鬧,春花似錦兼蕊、人聲如沸初厚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽产禾。三九已至排作,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亚情,已是汗流浹背妄痪。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留楞件,地道東北人衫生。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像土浸,于是被迫代替她去往敵國和親罪针。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容