函數(shù)調(diào)用
構(gòu)造器
構(gòu)造器(constructor)被調(diào)用時(shí)候會(huì)發(fā)生:
- 創(chuàng)建一個(gè)新對(duì)象
- 傳遞給構(gòu)造器的對(duì)象是this參數(shù)又沾,從而成為構(gòu)造器的函數(shù)上下文
- 如果沒有顯式的返回值衍锚,新創(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ū)別:
- 作為方法調(diào)用诫舅,this即上下文對(duì)象指向方法的擁有者
var a = {
getname(){}
}
a.getname();
- 作為全局對(duì)象進(jìn)行調(diào)用河爹,this指向window。
- 作為構(gòu)造器進(jìn)行調(diào)用衙解,this指向新創(chuàng)建的對(duì)象實(shí)例。
- 被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
上述代碼的過程:
- 在引用對(duì)象的一個(gè)屬性時(shí),首先檢查該對(duì)象本身是否擁有該屬性嘉抒,如果有零聚,則直接返回。
- 如果沒有就查找該對(duì)象的prototype上是否有該屬性些侍,如果有隶症,則返回,
- 如果該對(duì)象上的prototype也沒有就在其父級(jí)(有的話)上的prototype上查找娩梨。
- 查找到了返回沿腰,沒有查找到,就返回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á)式申明
有兩種方法:
- 正則字面量
var pattern = /test/;
- 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)義
比如需要匹配“[^]/用這種方式去匹配特殊字符脏里。另外"\"是用于匹配反斜杠""的她我,也是正常的規(guī)則。
匹配開始和匹配結(jié)束
/^test/表示字符串必須以test開頭
/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+",就表示將字符串中所有的空格都去掉随常。
匹配換行符
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下,一般使用addEventListener
和removeEventListener
事件來綁定和解綁事件序目。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:感覺翻譯的不太好。一周讀完