国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

js編程中經(jīng)常遇到的一些問(wèn)題(持續(xù)更新)

willin / 1367人閱讀

摘要:一前言本文適合有一定開發(fā)基礎(chǔ)的讀者,文章涉及開發(fā)中經(jīng)常遇到的一些令人疑惑的問(wèn)題,理解這些問(wèn)題有助于我們快速提升對(duì)這門語(yǔ)言的理解和應(yīng)用能力。

一:前言

本文適合有一定JS開發(fā)基礎(chǔ)的讀者,文章涉及開發(fā)中經(jīng)常遇到的一些令人疑惑的問(wèn)題,理解這些問(wèn)題有助于我們快速提升對(duì)JS這門語(yǔ)言的理解和應(yīng)用能力。文章只講述具體問(wèn)題中的關(guān)鍵問(wèn)題,不涵蓋全面的知識(shí)點(diǎn)。如想了解具體的知識(shí),可以參考筆者博客的相關(guān)文章。

二:正文 1.丟失的this

在實(shí)際應(yīng)用中, this的指向大致分為以下四種:
(1)作為對(duì)象方法的調(diào)用
(2)作為普通函數(shù)調(diào)用
(3)構(gòu)造器調(diào)用
(4)Function.prototype.call或Function.prototype.apply

1-1閱讀下面代碼:

//1.作為對(duì)象方法的調(diào)用this總是指向那個(gè)對(duì)象
window.name = "globalName";
var getName = function(){
    return this.name;
};
console.log( getName() ); // 輸出:globalName
//2.作為普通函數(shù)的調(diào)用:非嚴(yán)格模式下this總是指向window,嚴(yán)格模式下 undefined
window.name = "globalName";
var myObject = {
    name: "sven",
    getName: function(){
        return this.name;
    }
};
var getName = myObject.getName;//關(guān)鍵:這里保留了一個(gè)普通函數(shù)的引用
console.log( getName() ); // globalName

通過(guò)以上兩個(gè)對(duì)比,理解使用方法不同,this指向不同

1-2閱讀下面的代碼:

var getId = function( id ){
    return document.getElementById( id );
};
getId( "div1" );

//我們也許思考過(guò)為什么不能用下面這種更簡(jiǎn)單的方式:
var getId = document.getElementById;
getId( "div1" );

document.getElementById方法需要用到this。這個(gè)this本來(lái)被期望指向document,當(dāng)getElementById被當(dāng)作 document的屬性被調(diào)用時(shí),方法內(nèi)部的this確實(shí)是指向document.
但是當(dāng)使用getId來(lái)引用document.getElementById之后,在調(diào)用getId,此時(shí)就變成了普通函數(shù)調(diào)用,內(nèi)部的this就指向了window。
利用call或者apply更正this指向:
//我們可以嘗試?yán)胊pply 把document 當(dāng)作this 傳入getId 函數(shù),幫助“修正”this:

document.getElementById = (function( func ){
    return function(){
        return func.apply( document, arguments );
    }
})( document.getElementById );

var getId = document.getElementById;
var div = getId( "div1" );
alert (div.id); // 輸出: div1
2.實(shí)現(xiàn)手動(dòng)綁定this

2-1:bind方法的兼容寫法

var bind = Function.prototype.bind || function( context ){
        var self = this; // 保存原函數(shù)
        return function(){ // 返回一個(gè)新的函數(shù)
            return self.apply( context, arguments ); // 執(zhí)行新的函數(shù)的時(shí)候,會(huì)把之前傳入的context當(dāng)作新函數(shù)體內(nèi)的this
        }
    };
3.閉包

3-1.現(xiàn)在來(lái)看看下面這段代碼:

var func = function(){
    var a = 1;
    return function(){
        a++;
        alert ( a );
    }
};

var f = func();

f(); // 輸出:2
f(); // 輸出:3
f(); // 輸出:4
f(); // 輸出:5

當(dāng)執(zhí)行f = func()時(shí),f返回了一個(gè)匿名函數(shù)的引用,它可以訪問(wèn)到func()被調(diào)用時(shí)產(chǎn)生的環(huán)境,而局部變量a一直處在這個(gè)環(huán)境里。這個(gè)變量就有了不被銷毀的理由,這里就產(chǎn)生了一個(gè)閉包結(jié)構(gòu)。
3-2常見(jiàn)的閉包的問(wèn)題:




    



    
1
2
3
4
5

3-3.利用閉包延續(xù)局部變量的壽命

//img 對(duì)象經(jīng)常用于進(jìn)行數(shù)據(jù)上報(bào),如下所示:
    var report = function( src ){
    var img = new Image();
        img.src = src;
    };
    report( "http://xxx.com/getUserInfo" );
//丟失數(shù)據(jù)的原因是img是report函數(shù)中的局部變量,當(dāng)函數(shù)調(diào)用之后局部變量就銷毀了,而此時(shí)或許還沒(méi)來(lái)得及發(fā)起http請(qǐng)求
    //現(xiàn)在我們把img 變量用閉包封閉起來(lái),便能解決請(qǐng)求丟失的問(wèn)題:
    var report = (function(){
        var imgs = [];
        return function( src ){
            var img = new Image();
            imgs.push( img );
            img.src = src;
        }
    })();

閉包與內(nèi)存管理
閉包會(huì)使一些數(shù)據(jù)無(wú)法被及時(shí)的銷毀,如果將來(lái)需要回收這些變量,我們可以手動(dòng)把這些變量設(shè)置為null。
跟閉包和內(nèi)存泄漏有關(guān)系的地方是,使用閉包的同時(shí)容易形成循環(huán)引用,如果閉包的作用域鏈中保存著一些DOM結(jié)點(diǎn),這時(shí)候就有可能造成內(nèi)存泄漏。

4.高階函數(shù)

(1)函數(shù)可以作為參數(shù)被傳遞
(2)函數(shù)可以作為返回值輸出
4-1.函數(shù)作為參數(shù)傳遞
Array.prototype.sort方法:

    var array = ["10","5","12","3"];
    array.sort();
    //array:["10","12","3","5"]
    //如代碼那樣,排序的結(jié)果并不是我們想要的,這與sort函數(shù)的比較規(guī)則有關(guān)系
    array.sort(function(a,b){return a-b;});
    //array:["3","5","10","12"]
    傳入一個(gè)比較的函數(shù),就可以按照數(shù)字大小的規(guī)則進(jìn)行正確的比較了。

4-2.函數(shù)作為返回值輸出

var getSingle = function ( fn ) {
        var ret;
        return function () {
            return ret || ( ret = fn.apply( this, arguments ) );
        };
    };

4-3.函數(shù)作為參數(shù)被傳遞并且返回另一個(gè)函數(shù)

var getScript = getSingle(function(){
        return document.createElement( "script" );
    });
    var script1 = getScript();
    var script2 = getScript();
    alert ( script1 === script2 ); // 輸出:true

4-4.高階函數(shù)應(yīng)用
(1)高階函數(shù)實(shí)現(xiàn)AOP
AOP(面向切面編程)的主要作用是把一些跟核心業(yè)務(wù)邏輯模塊無(wú)關(guān)的功能抽離出來(lái),這些業(yè)務(wù)邏輯無(wú)關(guān)的功能包括日志統(tǒng)計(jì)、控制安全、異常處理等。把這些功能抽離出來(lái)之后,再通過(guò)“動(dòng)態(tài)織入”的方式摻入業(yè)務(wù)邏輯模塊中。
下面代碼通過(guò)擴(kuò)展Function.prototype來(lái)實(shí)現(xiàn)把一個(gè)函數(shù)“動(dòng)態(tài)織入”

Function.prototype.before = function( beforefn ){
        var __self = this; // 保存原函數(shù)的引用
        return function(){ // 返回包含了原函數(shù)和新函數(shù)的"代理"函數(shù)
            beforefn.apply( this, arguments ); // 執(zhí)行新函數(shù),修正this
            return __self.apply( this, arguments ); // 執(zhí)行原函數(shù)
        }
    };

    Function.prototype.after = function( afterfn ){
        var __self = this;
        return function(){
            var ret = __self.apply( this, arguments );
            afterfn.apply( this, arguments );
            return ret;
        }
    };

    var func = function(){
        console.log( 2 );
    };

    func = func.before(function(){
        console.log( 1 );
    }).after(function(){
        console.log( 3 );
    });

func();

(2)柯里化
一個(gè)currying函數(shù)首先會(huì)接受一些參數(shù),接受了這些參數(shù)之后,該函數(shù)不會(huì)立即求值,而是繼續(xù)返回另外一個(gè)函數(shù),剛才傳入的參數(shù)在函數(shù)形成的閉包中被保存了下來(lái)。待到函數(shù)真正需要求值的時(shí)候,之前傳入的所有參數(shù)都會(huì)一次性用于求值。

一個(gè)經(jīng)典的柯里化:

function curry(fn){
        var arr1 = Array.prototype.slice.call(arguments,1);
        return function(){
            var arg2 = Array.prototype.slice.call(arguments);
            var array = arr1.concat(arr2);
            return fn.apply(null,array);
        }
    }

不斷累積的柯里化:

   var currying = function( fn ){
        var args = [];//外層函數(shù)變量:用來(lái)累積
        return function(){
            if ( arguments.length === 0 ){
                return fn.apply( this, args );
            }else{
                [].push.apply( args, arguments );
                return arguments.callee;
            }
        }
    };

(3)uncurrying

在javascript中,當(dāng)我們調(diào)用對(duì)象的某個(gè)方法時(shí),其實(shí)不用關(guān)心對(duì)象原本是否被設(shè)計(jì)為擁有這個(gè)方法,這是動(dòng)態(tài)類型語(yǔ)言的特點(diǎn),也就是常說(shuō)的鴨子類型思想。
同理,一個(gè)對(duì)象也未必只能使用它自己的方法,其實(shí)可以借用原本不屬于他的方法: call apply

Function.prototype.uncurrying = function () {
        var self = this;
        return function() {
            var obj = Array.prototype.shift.call( arguments );
            return self.apply( obj, arguments );
        };
    };

    var push = Array.prototype.push.uncurrying();
var obj = {
    "length": 1,
    "0": 1
};

push( obj, 2 );//將2使用push的方法作用到obj上
console.log( obj ); // 輸出:{0: 1, 1: 2, length: 2}
5.函數(shù)節(jié)流

函數(shù)節(jié)流也用到了高階函數(shù)的知識(shí),因?yàn)楸容^重要,所以單開了一個(gè)標(biāo)題。
javascript中的函數(shù)在大多數(shù)情況下都是由用戶主動(dòng)調(diào)用觸發(fā)的,除非是函數(shù)本身的實(shí)現(xiàn)不合理。但是在一些少數(shù)情況下,函數(shù)可能被很頻繁的調(diào)用,而造成大的性能問(wèn)題。
(1)函數(shù)被頻繁調(diào)用的場(chǎng)景

1.window.onresize事件
2.mousemove事件
3.上傳進(jìn)度

(2)函數(shù)節(jié)流的原理
解決函數(shù)觸發(fā)頻率太高的問(wèn)題,需要我們按照時(shí)間段來(lái)忽略一些事件請(qǐng)求。
(3)函數(shù)節(jié)流的代碼實(shí)現(xiàn)
詳情可以參考
Underscore.js#throttle
Underscore.js#debounce
簡(jiǎn)單實(shí)現(xiàn):
將即將被執(zhí)行的函數(shù)用steTimeout延時(shí)一段時(shí)間執(zhí)行。如果該次延時(shí)執(zhí)行還沒(méi)有完成,就忽略掉接下來(lái)調(diào)用該函數(shù)的請(qǐng)求。

var throttle = function ( fn, interval ) {
        var __self = fn, // 保存需要被延遲執(zhí)行的函數(shù)引用
        timer, // 定時(shí)器
        firstTime = true; // 是否是第一次調(diào)用
        return function () {
            var args = arguments,
            __me = this;
            if ( firstTime ) { // 如果是第一次調(diào)用,不需延遲執(zhí)行
                __self.apply(__me, args);
                return firstTime = false;
            }
            if ( timer ) { // 如果定時(shí)器還在,說(shuō)明前一次延遲執(zhí)行還沒(méi)有完成
                return false;

            timer = setTimeout(function () { // 延遲一段時(shí)間執(zhí)行
                clearTimeout(timer);
                timer = null;
                __self.apply(__me, args);
            }, interval || 500 );
        };
    };


    window.onresize = throttle(function(){
        console.log( 1 );
    }, 500 );

另一種實(shí)現(xiàn)函數(shù)節(jié)流的方法-分時(shí)函數(shù)

某些函數(shù)確實(shí)是用戶主動(dòng)調(diào)用的,但是因?yàn)橐恍┛陀^的原因,這些函數(shù)會(huì)嚴(yán)重的影響頁(yè)面的性能。
一個(gè)例子就是創(chuàng)建QQ好友列表。如果一個(gè)好友列表用一個(gè)節(jié)點(diǎn)表示,當(dāng)我們?cè)陧?yè)面中渲染這個(gè)列表的時(shí)候,可能要一次性的網(wǎng)頁(yè)面中創(chuàng)建成百上千個(gè)節(jié)點(diǎn)。

var ary = [];
for ( var i = 1; i <= 1000; i++ ){
    ary.push( i ); // 假設(shè)ary 裝載了1000 個(gè)好友的數(shù)據(jù)
};

var renderFriendList = function( data ){
    for ( var i = 0, l = data.length; i < l; i++ ){
        var div = document.createElement( "div" );
        div.innerHTML = i;
        document.body.appendChild( div );
    }
};

renderFriendList( ary );

在短時(shí)間內(nèi)網(wǎng)頁(yè)面中大量添加DOM節(jié)點(diǎn)顯然也會(huì)讓瀏覽器吃不消。
這個(gè)問(wèn)題的解決方案之一是下面的timeChunk函數(shù):讓創(chuàng)建節(jié)點(diǎn)的工作分批進(jìn)行

//第一個(gè)參數(shù)是創(chuàng)建節(jié)點(diǎn)時(shí)需要的數(shù)據(jù),第二個(gè)參數(shù)封裝了創(chuàng)建節(jié)點(diǎn)邏輯的函數(shù),第三個(gè)參數(shù)表示每一批創(chuàng)建節(jié)點(diǎn)的數(shù)量。
var timeChunk = function( ary, fn, count ){
    var obj,
    t;
    var len = ary.length;
    var start = function(){
        for ( var i = 0; i < Math.min( count || 1, ary.length ); i++ ){
            var obj = ary.shift();
            fn( obj );
        }
    };
    return function(){
        t = setInterval(function(){
        if ( ary.length === 0 ){ // 如果全部節(jié)點(diǎn)都已經(jīng)被創(chuàng)建好
            return clearInterval( t );
        }
        start();
        }, 200 ); // 分批執(zhí)行的時(shí)間間隔,也可以用參數(shù)的形式傳入
    };
};

var ary = [];
for ( var i = 1; i <= 1000; i++ ){
    ary.push( i );
};
var renderFriendList = timeChunk( ary, function( n ){
    var div = document.createElement( "div" );
    div.innerHTML = n;
    document.body.appendChild( div );
}, 8 );
renderFriendList();
6.惰性加載函數(shù)

在web開發(fā)中,因?yàn)闉g覽器之間的實(shí)現(xiàn)差異,一些嗅探工作總是不可避免。

var addEvent = function( elem, type, handler ){
        if ( window.addEventListener ){
            return elem.addEventListener( type, handler, false );

        }
        if ( window.attachEvent ){
            return elem.attachEvent( "on" + type, handler );
        }
    };

這個(gè)函數(shù)的缺點(diǎn)是,當(dāng)它每次被調(diào)用的時(shí)候都會(huì)執(zhí)行里面的if條件分支。
下面這個(gè)函數(shù)雖然仍然有一些分支判斷,但是在第一次進(jìn)入條件分支之后,在函數(shù)內(nèi)部就會(huì)重寫這個(gè)函數(shù),重寫之后的函數(shù)就是我們希望的addEvent函數(shù)。

  var addEvent = function(ele,type,handler){
        if(window.addEventListener){
            addEvent = function(ele,type,handler){
                elem.addEventListener( type, handler, false );
            }
        }
        if(window.attachEvent){
            addEvent = function(ele,type,handler){
                elem.attachEvent( "on" + type, handler );
            }
        }
        addEvent(ele,type,handler);
    }
三:結(jié)語(yǔ)

文章介紹的都是JS需要掌握的重點(diǎn)又是難點(diǎn)的知識(shí),需要多動(dòng)手實(shí)踐才能理解。有關(guān)相關(guān)知識(shí)的詳細(xì)講解,可以參考筆者的相關(guān)文章。當(dāng)然 ,最好的方式是去谷歌然后自己動(dòng)手實(shí)踐。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/82784.html

相關(guān)文章

  • [譯] 如何恰當(dāng)?shù)貙W(xué)習(xí) JavaScript

    摘要:原文鏈接恰當(dāng)?shù)貙W(xué)習(xí)適合第一次編程和非的程序員持續(xù)時(shí)間到周前提無(wú)需編程經(jīng)驗(yàn)繼續(xù)下面的課程。如果你沒(méi)有足夠的時(shí)間在周內(nèi)完成全部的章節(jié),學(xué)習(xí)時(shí)間盡力不要超過(guò)周。你還不是一個(gè)絕地武士,必須持續(xù)使用你最新學(xué)到的知識(shí)和技能,盡可能地經(jīng)常持續(xù)學(xué)習(xí)和提高。 原文鏈接:How to Learn JavaScript Properly 恰當(dāng)?shù)貙W(xué)習(xí) JavaScript (適合第一次編程和非 JavaSc...

    Jason 評(píng)論0 收藏0
  • 前端開發(fā)負(fù)責(zé)人修煉指北

    摘要:大家好,我叫,江湖人稱吃土小叉,目前擔(dān)任公司的前端負(fù)責(zé)人半年多了,一路上摸爬滾打,歷經(jīng)團(tuán)隊(duì)人員變動(dòng),近日頗有感觸,于是結(jié)合自己近半年的前端負(fù)責(zé)人實(shí)踐經(jīng)驗(yàn),權(quán)當(dāng)作一個(gè)學(xué)習(xí)記錄,整理歸納一下小作坊團(tuán)隊(duì)前端負(fù)責(zé)人的修煉要點(diǎn)大部分只是記錄了關(guān)鍵詞, 大家好,我叫XX,江湖人稱吃土小2叉,目前擔(dān)任公司的前端負(fù)責(zé)人半年多了,一路上摸爬滾打,歷經(jīng)團(tuán)隊(duì)人員變動(dòng),近日頗有感觸,于是結(jié)合自己近半年的前端負(fù)...

    Drummor 評(píng)論0 收藏0
  • React.js 常見(jiàn)問(wèn)題

    摘要:我們常常會(huì)收到一些有趣的問(wèn)題,但大多數(shù)問(wèn)題都是常見(jiàn)問(wèn)題。我創(chuàng)建這個(gè)資源為了幫助學(xué)習(xí)者遇到這些常見(jiàn)的問(wèn)題時(shí)提供一定幫助。這些是表示沒(méi)有任何子節(jié)點(diǎn)的元素的標(biāo)記。不綁定處理程序方法我把這個(gè)留到最后,因?yàn)檫@是一個(gè)大問(wèn)題,一個(gè)很常見(jiàn)的問(wèn)題。 在 jsComplete,我們管理一個(gè)專門用于幫助編程學(xué)習(xí)者 slack 帳戶。我們常常會(huì)收到一些有趣的問(wèn)題,但大多數(shù)問(wèn)題都是常見(jiàn)問(wèn)題。 我創(chuàng)建這個(gè)資源為了...

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

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

0條評(píng)論

閱讀需要支付1元查看
<