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

資訊專欄INFORMATION COLUMN

關(guān)于JavaScript函數(shù)調(diào)用的幾種模式

鄒強(qiáng) / 537人閱讀

摘要:函數(shù)的調(diào)用有五種模式方法調(diào)用模式,函數(shù)調(diào)用模式,構(gòu)造器調(diào)用模式,調(diào)用模式以及回調(diào)模式,下面分別對這幾種模式進(jìn)行說明。構(gòu)造器調(diào)用模式構(gòu)造函數(shù)的調(diào)用方式被稱為構(gòu)造器調(diào)用模式,這是模擬類繼承式語言的一種調(diào)用方式。

函數(shù)的調(diào)用有五種模式:方法調(diào)用模式,函數(shù)調(diào)用模式,構(gòu)造器調(diào)用模式,apply/call調(diào)用模式以及回調(diào)模式,下面分別對這幾種模式進(jìn)行說明。

1.函數(shù)調(diào)用與方法調(diào)用模式:

1.1 聲明一個(gè)函數(shù)并調(diào)用它就是函數(shù)調(diào)用模式,這是最簡單的調(diào)用,但其中也關(guān)系到this的指向問題。普通函數(shù)是將this默認(rèn)綁定到全局對象,而箭頭函數(shù)時(shí)不綁定this的,在函數(shù)所在的父作用域外面this指向哪里,在箭頭函數(shù)內(nèi)部this也指向哪里。

    function show(name) {
        console.log(name);
    }

    show("shotar");                // shotar

    // 普通函數(shù)的符符作用域this指向全局作用域,在調(diào)用的時(shí)候再一次綁定this到全局作用域
    function say() {
        console.log(this);
    }

    say();                        // 瀏覽器環(huán)境輸出window  node環(huán)境輸出global

    // 箭頭函數(shù)父作用域的this指向全局對象,調(diào)用的時(shí)候并沒有綁定this,而是繼承父作用域后指向全局對象
    var sayName = () => {
        console.log(this);
    }

    sayName()                     // window

1.2 方法調(diào)用時(shí)將一個(gè)函數(shù)作為對象的方法調(diào)用,作為方法調(diào)用的函數(shù)會(huì)將this綁定到該對象,但如果方法內(nèi)部再嵌套一個(gè)函數(shù),內(nèi)部函數(shù)再次調(diào)用的時(shí)候又屬于函數(shù)調(diào)用模式,此時(shí)this又將綁定到全局對象。

    window.name = "Jane";        // node環(huán)境下是global
    var obj = {
        name: "shotar",
        sayName: function() {
            console.log(1, this.name);
            sayWindowName();

            function sayWindowName() {
                console.log(2, this.name);
            }
        }
    };

    obj.sayName();                // 1, shotar      2, Jane

如果想讓內(nèi)部函數(shù)(sayWindowName)指向該對象也很簡單,在此列舉三種方法。第一種是在外部將this保存到一個(gè)變量里面,再在內(nèi)部函數(shù)中使用即可。

    window.name = "Jane";
    var obj = {
        name: "shotar",
        sayName: function() {
            var _this = this;
            console.log(1, this.name);
            sayWindowName();

            function sayWindowName() {
                console.log(2, _this.name);
            }
        }
    };

    obj.sayName();                // 1, shotar      2, shotar

第二種解決辦法是使用ES6的箭頭函數(shù),箭頭函數(shù)不綁定this,父作用域的this是哪個(gè)對象在箭頭函數(shù)中的this仍然是哪個(gè)對象(注意:箭頭函數(shù)只能使用函數(shù)字面量的形式命名函數(shù)名,調(diào)用也要在語句之后)。

    window.name = "Jane";
    var obj = {
        name: "shotar",
        sayName: function() {
            console.log(1, this.name);

            var sayWindowName = () => {
                console.log(2, _this.name);
            };

            sayWindowName();
        }
    };

    obj.sayName();                // 1, shotar      2, shotar

第三種使用call或apply方法是改變內(nèi)部函數(shù)的this值。

    window.name = "Jane";
    var obj = {
        name: "shotar",
        sayName: function() {
            console.log(1, this.name);
            sayWindowName.call(this);        // 或 sayWindowName.apply(this);

            function sayWindowName() {
                console.log(2, this.name);
            }
        }
    };

    obj.sayName();                // 1, shotar      2, shotar

在此說明一下阮大大在ES6標(biāo)準(zhǔn)入門里面列舉的關(guān)于箭頭函數(shù)this指向的例子,因?yàn)樵趂oo函數(shù)的作用域下指向window的,使用函數(shù)調(diào)用模式調(diào)用foo函數(shù),setTimeout內(nèi)的箭頭函數(shù)不綁定this,還是指向父作用域foo函數(shù)所指向的this。foo是普通函數(shù),他將this指向全局對象,因此箭頭函數(shù)也指向全局變量。這時(shí)會(huì)打印undefined,為什么又會(huì)打印出undefined呢,這是因?yàn)樵诼暶鱥d的時(shí)候使用了var關(guān)鍵字,他是一個(gè)變量并不是全局對象(window或global)的屬性,如果將var id = 21;這句改為window.id = 21;(或者global.id = 21)后將打印出21。使用call方法調(diào)用會(huì)改變this的值,下面到call/apply調(diào)用模式的時(shí)候會(huì)講到。

    function foo() {
        setTimeout(() => {
            console.log("id:", this.id);
        }, 100);
    }

    var id = 21;

    foo();

    foo.call({ id: 42 });        // id: 42

1.3 關(guān)于函數(shù)this指向問題
普通函數(shù)的this是會(huì)被綁定的,根據(jù)調(diào)用方式的不同綁定不同的對象到this(this只能綁定對象),而箭頭函數(shù)是不綁定this的。有這樣一道面試題:

    window.bar = 2
    var obj = {
        bar: 1,
        foo: function() {
            return this.bar;
        }
    };

    var foo = obj.foo;

    console.log(obj.foo()); // 1
    console.log(foo());        // 2

JavaScript的this設(shè)計(jì)很內(nèi)存里的數(shù)據(jù)結(jié)構(gòu)有很大的關(guān)系。當(dāng)把一個(gè)對象賦給一個(gè)變量的時(shí)候,大家都知道是引用關(guān)系,上面的obj是一個(gè)地址,指向那個(gè)對象,而在對象存儲的時(shí)候,其屬性(方法)的值也是同樣的存儲形式,每個(gè)屬性對應(yīng)一個(gè)屬性描述對象,舉例來講,上面obj的bar屬性其實(shí)是以下面的形式保存起來的。

    bar: {
        [[value]]: 1,
        [[configurable]]: true,
        [[enumerable]]: true,
        [[writable]]: true
    }

其屬性的值被保存在[[value]]中。但如果屬性的值是個(gè)對象(函數(shù)也是對象)呢?此時(shí)JavaScript引擎會(huì)將對象的地址保存在描述符對象的[[value]]位置,像上面的foo屬性(方法)則是這樣保存的:

    foo: {
        [[value]]: 對象的地址,
        [[configurable]]: true,
        [[enumerable]]: true,
        [[writable]]: true
    }

函數(shù)是個(gè)多帶帶的值,因此他可以在任何不同的上下文環(huán)境中執(zhí)行,也正因?yàn)槿绱耍斜匾枰环N機(jī)制能夠在函數(shù)內(nèi)部獲得當(dāng)前的執(zhí)行上下文(context),因此this就出現(xiàn)了。在上面的那道面試題中,是將該函數(shù)的地址賦給變量foo。通過foo變量調(diào)用時(shí),其是在全局作用域下執(zhí)行,因此this指向全局對象。如圖1:

而使用obj.foo執(zhí)行時(shí),函數(shù)是在obj環(huán)境下運(yùn)行,如圖2,所以this是指向obj的。上面提到普通函數(shù)是綁定this值,this值指得是當(dāng)前運(yùn)行環(huán)境,當(dāng)在obj環(huán)境下調(diào)用時(shí)指向obj,而在全局調(diào)用時(shí)指向全局對象。所以this是在調(diào)用時(shí)才確定值,并不是在聲明時(shí)就綁定值。

2.call/apply調(diào)用模式

call和apply都是Function.prototype中的方法,可以通過Function.prototype.hasOwnProperty("call")驗(yàn)證。因此每一個(gè)函數(shù)或者方法都可通過call或apply調(diào)用,call和apply都是函數(shù)上的方法,每聲明一個(gè)函數(shù),就像prototype屬性一樣,都會(huì)有call和apply方法。每個(gè)函數(shù)或方法都可以通過call或者apply改變當(dāng)前的執(zhí)行上下文,他們的第一個(gè)參數(shù)就是要將this綁定的值。區(qū)別是后面的傳參形式不同,前者是將參數(shù)逐個(gè)傳入調(diào)用的函數(shù)中,而apply是將參數(shù)作為一個(gè)數(shù)組傳給要調(diào)用的函數(shù)。就拿那道面試題做例子:

    window.bar = 2
    var obj = {
        bar: 1,
        foo: function() {
            return this.bar;
        }
    };

    var foo = obj.foo;

    // ①
    foo.call(obj);            // 1
    // ②
    obj.foo.call(window);    // 2
    // ③
    foo.call({bar: 3})        // 3

①如果foo是普通的調(diào)用,其this是指向全局對象的,而通過call改變將this綁定到obj后,this將指向obj。我們可以這樣理解,foo是這樣調(diào)用的obj.foo()
②這種調(diào)用方式我們可以這樣理解,foo是obj的方法,就當(dāng)他是一個(gè)普通的函數(shù),相當(dāng)于window.foo這樣調(diào)用,那么this就是指向全局對象的。
③這種調(diào)用方式是將{bar: 3}作為this的綁定對象,這樣調(diào)用foo就相當(dāng)于{bar: 3}.foo(),this指向{bar: 3}。

3.構(gòu)造器調(diào)用模式:
構(gòu)造函數(shù)的new調(diào)用方式被稱為構(gòu)造器調(diào)用模式,這是模擬類繼承式語言的一種調(diào)用方式。在使用new操作符調(diào)用函數(shù)時(shí),函數(shù)內(nèi)部將this綁定到一個(gè)新對象并返回。如下

    var Person = function(name) {
        this.name = name;
    };

    var shotar = new Person(shotar);
    // 為了區(qū)別于普通函數(shù),約定構(gòu)造函數(shù)的首字母大寫。使用new操作內(nèi)部會(huì)替你做以下操作:
    Person(name) {
        // 以下都是使用new操作符時(shí)內(nèi)部做的事
        // var obj = new Object();
        // this = obj;
        // obj.name = name;
        // obj.prototype = Person.prototype;

        // return obj;
    }

如果構(gòu)造函數(shù)內(nèi)部返回了一個(gè)不是對象的值,則new會(huì)忽略其返回值而返回新建的對象,如果返回的是一個(gè)對象則將其返回。另外,如果不使用new操作符調(diào)用,并不會(huì)在編譯時(shí)報(bào)錯(cuò),這是非常糟糕的事情,因此,我們通常會(huì)在調(diào)用的時(shí)候檢查是否為new操作符調(diào)用,如下:

    function Person(name) {
        if (this instanceof Person) {
            this.name = name;
        } else {
            return new Person(name);
        }
    }

4.回調(diào)模式
回調(diào)函數(shù)是在滿足某種情況或者達(dá)到某種要求時(shí)立即調(diào)用。回調(diào)函數(shù)通常作為函數(shù)的參數(shù)傳入,其本質(zhì)也還是一種普通的函數(shù),只是在特定的情況下執(zhí)行而已,先看一個(gè)例子:

    function sayName(obj) {
        var fullName = "";
        if (obj.firstName && obj.lastName) {
            fullName = typeof obj.computedFullName === "function" ?
                obj.computedFullName() :
                obj.lastName + " " + obj.firstName;
        return fullName;
    }

    var obj = {
        firstName: "Sanfeng",
        lastName: "Zhang",

        computedFullName: function() {
            return this.lastName + " " + this.firstName;
        }
    };

    sayName(obj);            // Zhang Sanfeng

此處的computedName就是一個(gè)回調(diào)函數(shù),在給sayName函數(shù)傳值的時(shí)候,我們傳入了一個(gè)對象,前兩個(gè)屬性都是直接在sayName中使用,如果滿足這兩個(gè)屬性都有值,那就調(diào)用obj的computedName方法(也就是函數(shù)),在此處調(diào)用就稱他為回調(diào)函數(shù),回調(diào)函數(shù)常用于異步操作的場合,比如ajax請求,當(dāng)請求成功并返回?cái)?shù)據(jù)時(shí)再執(zhí)行回調(diào)函數(shù)。一般也用于同步阻塞的場景下,比如執(zhí)行某些操作后執(zhí)行回調(diào)函數(shù)。請先看下面的異步情況的例子:

    function ajax(callback) {
        var xhr = new XMLHttpReauest(); 

        if (xhr.readystate === 4 && xhr.status === 200) {
            typeof callback === "function" && callback();
        } else {
            alert("請求失敗!")
        }

        xhr.open("get", url);
        xhr.send();
    }

    var fn = function() {
        alert("請求成功!");
    };

    ajax(fn);

這里會(huì)有一個(gè)問題,如何給回調(diào)函數(shù)傳參,讓回調(diào)函數(shù)在里面處理一些問題,這里我們就可以用到call或者apply方法了。比如有這樣一個(gè)問題:統(tǒng)計(jì)若干個(gè)人的考試成績,只有90分以上的才發(fā)獎(jiǎng)學(xué)金,請看下面同步阻塞的例子:

    function startGive(arr, giveMoney) {
        // 先把分?jǐn)?shù)超過90分的過濾出來
        let adult = arr.filter(item => item > 90);

        // 將過濾結(jié)果傳入回調(diào)函數(shù),發(fā)獎(jiǎng)金給他們
        return giveMoney.call(null, adult);
    }

    let giveBonuses = function(arr) {
        return arr.map(item => item + "giveMoney");
    };

    console.log(startGive([70, 80, 92, 96, 85], giveBonuses));        // [ "92giveMoney", "96giveMoney" ]

上面的例子主要是在將分?jǐn)?shù)在90分以上的過濾出來之后再執(zhí)行操作。回調(diào)傳參還可以通過傳遞匿名函數(shù)的形式接收該參數(shù),如下例子:

    function fn(arg1, arg2, callback){
        var num = Math.ceil(Math.random() * (arg1 - arg2) + arg2);
        callback(num);
    }
     
    fn(10, 20, function(num){
        console.log("Callback called! Num: " + num); 
    }); 

5.總結(jié)
本文講了關(guān)于函數(shù)調(diào)用的五種模式。五種模式包括函數(shù)調(diào)用模式、方法調(diào)用模式、call/apply調(diào)用模式、構(gòu)造器調(diào)用模式和回調(diào)模式。其中前三種調(diào)用模式類似,主要會(huì)涉及到this的指向問題,第四種調(diào)用方式總返回一個(gè)對象,并將this綁定到此對象。回調(diào)模式屬于前四種模式中的一種,可以是函數(shù)調(diào)用模式,也可以是方法調(diào)用模式,回調(diào)的使用很靈活,其主要場景是用于異步操作或同步阻塞操作的場合。

本文參考《JavaScript語言精粹》一書的函數(shù)章節(jié)及阮大大的《JavaScript 的 this 原理》一文撰寫而出,文中若有表述不妥或是知識點(diǎn)有誤之處,歡迎留言指正批評!

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

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

相關(guān)文章

  • 影響JavaScript中this指向幾種函數(shù)調(diào)用方法

    摘要:前言初學(xué)總會(huì)對指向感到疑惑,想要深入學(xué)習(xí),必須先理清楚和相關(guān)的幾個(gè)概念。中總是指向一個(gè)對象,但具體指向誰是在運(yùn)行時(shí)根據(jù)函數(shù)執(zhí)行環(huán)境動(dòng)態(tài)綁定的,而并非函數(shù)被聲明時(shí)的環(huán)境。除去不常用的和的情況,具體到實(shí)際應(yīng)用中,指向大致可以分為以下種。 前言 初學(xué)javascript總會(huì)對this指向感到疑惑,想要深入學(xué)習(xí)javascript,必須先理清楚和this相關(guān)的幾個(gè)概念。javascript中t...

    Drinkey 評論0 收藏0
  • JavaScript 嚴(yán)格模式下this幾種指向

    摘要:前言曾經(jīng)被中的弄暈了,今天整理總結(jié)一下在嚴(yán)格模式下的幾種指向。嚴(yán)格模式構(gòu)造函數(shù)中的事件處理函數(shù)中的在嚴(yán)格模式下,在事件處理函數(shù)中,指向觸發(fā)事件的目標(biāo)對象。 前言 曾經(jīng)被 JavaScript 中的 this 弄暈了,今天整理總結(jié)一下在嚴(yán)格模式下 this 的幾種指向。 1. 全局作用域中的this 在嚴(yán)格模式下,在全局作用域中,this指向window對象 use stric...

    smallStone 評論0 收藏0
  • JS常用幾種異步流程控制

    摘要:雖然這個(gè)模式運(yùn)行效果很不錯(cuò),但是如果嵌套了太多的回調(diào)函數(shù),就會(huì)陷入回調(diào)地獄。當(dāng)需要跟蹤多個(gè)回調(diào)函數(shù)的時(shí)候,回調(diào)函數(shù)的局限性就體現(xiàn)出來了,非常好的改進(jìn)了這些情況。 JavaScript引擎是基于單線程 (Single-threaded) 事件循環(huán)的概念構(gòu)建的,同一時(shí)刻只允許一個(gè)代碼塊在執(zhí)行,所以需要跟蹤即將運(yùn)行的代碼,那些代碼被放在一個(gè)任務(wù)隊(duì)列 (job queue) 中,每當(dāng)一段代碼準(zhǔn)...

    Barry_Ng 評論0 收藏0
  • javascript高級程序設(shè)計(jì)》第六章 讀書筆記 之 javascript對象幾種創(chuàng)建方式

    摘要:三種使用構(gòu)造函數(shù)創(chuàng)建對象的方法和的作用都是在某個(gè)特殊對象的作用域中調(diào)用函數(shù)。這種方式還支持向構(gòu)造函數(shù)傳遞參數(shù)。叫法上把函數(shù)叫做構(gòu)造函數(shù),其他無區(qū)別適用情境可以在特殊的情況下用來為對象創(chuàng)建構(gòu)造函數(shù)。 一、工廠模式 工廠模式:使用字面量和object構(gòu)造函數(shù)會(huì)有很多重復(fù)代碼,在此基礎(chǔ)上改進(jìn)showImg(https://segmentfault.com/img/bVbmKxb?w=456&...

    xiaotianyi 評論0 收藏0
  • 基本方法筆記 - 收藏集 - 掘金

    摘要:探討判斷橫豎屏的最佳實(shí)現(xiàn)前端掘金在移動(dòng)端,判斷橫豎屏的場景并不少見,比如根據(jù)橫豎屏以不同的樣式來適配,抑或是提醒用戶切換為豎屏以保持良好的用戶體驗(yàn)。 探討判斷橫豎屏的最佳實(shí)現(xiàn) - 前端 - 掘金在移動(dòng)端,判斷橫豎屏的場景并不少見,比如根據(jù)橫豎屏以不同的樣式來適配,抑或是提醒用戶切換為豎屏以保持良好的用戶體驗(yàn)。 判斷橫豎屏的實(shí)現(xiàn)方法多種多樣,本文就此來探討下目前有哪些實(shí)現(xiàn)方法以及其中的優(yōu)...

    maochunguang 評論0 收藏0

發(fā)表評論

0條評論

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