JavaScript高級程序設(shè)計——this

js-this

前言

本來this應(yīng)該放在《上下文環(huán)境和作用域》中來講半醉,結(jié)果發(fā)現(xiàn)自己整理的時候,例子越來越多式塌,所以單獨(dú)寫一篇用于加深理解博敬,以后工作或項目中發(fā)現(xiàn)一些this相關(guān)問題可以進(jìn)一步完善文章的例子。

this

概念

在函數(shù)中this到底取何值峰尝,是在函數(shù)真正被調(diào)用執(zhí)行的時候確定的偏窝,函數(shù)定義的時候確定不了

因為this的取值是執(zhí)行上下文環(huán)境的一部分,每次調(diào)用函數(shù)武学,都會產(chǎn)生一個新的執(zhí)行上下文環(huán)境祭往。

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

所謂構(gòu)造函數(shù)就是用來new對象的函數(shù)。其實(shí)嚴(yán)格來說火窒,所有的函數(shù)都可以new一個對象硼补,但是有些函數(shù)的定義是為了new一個對象,而有些函數(shù)則不是熏矿。另外注意已骇,構(gòu)造函數(shù)的函數(shù)名第一個字母大寫(規(guī)則約定)。例如:Object票编、Array拷姿、Function等枉氮。

function Foo() {
            this.name = "yzh";
            this.year = 1996;
            console.log(this); //Object { name: "yzh", year: 1998 }
        }
        var f1 = new Foo();
        console.log(f1.name); //yzh
        console.log(f1.year); //1996

以上代碼中,如果函數(shù)作為構(gòu)造函數(shù)用,那么其中的this就代表它即將new出來的對象拘泞。

注意,以上僅限newFoo()的情況逞怨,即Foo函數(shù)作為構(gòu)造函數(shù)的情況穆碎。如果直接調(diào)用Foo函數(shù),而不是new Foo()论泛,情況就大不一樣了揩尸。

function Foo() {
            this.name = "yzh";
            this.year = 1996;
            console.log(this); //Object { name: "yzh", year: 1998 }
        }
        Foo();  //window

這種情況下this是window。

函數(shù)作為對象的一個屬性

如果函數(shù)作為對象的一個屬性時屁奏,并且作為對象的一個屬性被調(diào)用時岩榆,函數(shù)中的this指向該對象。

var obj = {
            x: 10,
            fn: function() {
                console.log(this); //Object { x: 10, fn: fn() }
                console.log(this.x); //10
            }
        };
        obj.fn();

以上代碼中,fn不僅作為一個對象的一個屬性勇边,而且的確是作為對象的一個屬性被調(diào)用犹撒。結(jié)果this就是obj對象。

如果fn函數(shù)不作為obj的一個屬性被調(diào)用粒褒,會是什么結(jié)果呢识颊?

var obj = {
            x: 10,
            fn: function() {
                console.log(this); //window
                console.log(this.x); //undefined
            }
        };
        var f1 = obj.fn;
        f1();

如上代碼,如果fn函數(shù)被賦值到了另一個變量中奕坟,并沒有作為obj的一個屬性被調(diào)用祥款,那么this的值就是window,this.x為undefined月杉。

函數(shù)用call或者apply調(diào)用

為了防止看不懂這塊先理解下基礎(chǔ)并重要的東西

函數(shù)內(nèi)部屬性

在函數(shù)內(nèi)部刃跛,有兩個特殊的對象:arguments和this.
主要介紹下arguments,它是類數(shù)組對象,包含傳入函數(shù)的所有參數(shù)苛萎,這個對象還有一個叫callee的屬性桨昙,該屬性為一個指針,指向擁有這個arguments對象的函數(shù)腌歉。

這個例子主要用于消除函數(shù)的執(zhí)行與同名函數(shù)的緊密耦合現(xiàn)象蛙酪。代碼如下:

function factorial(num) {
            if (num <= 1) {
                return 1;
            } else {
               // return num * factorial(num - 1);
                //1.一般的遞歸算法運(yùn)用
                return num * arguments.callee(num - 1) 
                //2.更好的做法
            }
        }

        var trueFactorial = factorial;

        factorial = function() {
            return 0;
        };

        alert(trueFactorial(5)); //120
        alert(factorial(5)); //0

函數(shù)屬性

每個函數(shù)都包含兩個屬性:length和prototype.
length表示函數(shù)希望接受的命名參數(shù)的個數(shù)

function sayName(name){
            alert(name);
        }      
        
        function sum(num1, num2){
            return num1 + num2;
        }
        
        function sayHi(){
            alert("hi");
        }
        
        alert(sayName.length);  //1
        alert(sum.length);      //2
        alert(sayHi.length);    //0

prototype屬性這里不再重復(fù)介紹。

函數(shù)方法

每個函數(shù)都包含兩個非繼承而來的方法:apply()和call(),這兩個方法的用途都是在特定的作用域中調(diào)用函數(shù)翘盖,實(shí)際上等于設(shè)置函數(shù)體內(nèi)的this對象值桂塞。

apply()方法接受兩個參數(shù):一個是在其中運(yùn)行函數(shù)的作用域,另一個是參數(shù)數(shù)組最仑。

function sum(num1, num2){
            return num1 + num2;
        }
        
        function callSum1(num1, num2){
            return sum.apply(this, arguments);
        }
        
        function callSum2(num1, num2){
            return sum.apply(this, [num1, num2]);
        }
        
        alert(callSum1(10,10));   //20
        alert(callSum2(10,10));   //20

callsSum1()執(zhí)行sum()函數(shù)時傳入this作為this值(在全局作用域中調(diào)用藐俺,所以傳入的對象為window對象)下面的例子同理。

call()方法與apply()方法差不多泥彤,區(qū)別在于接受參數(shù)的方式不同欲芹。簡單來說就是:傳遞給函數(shù)的參數(shù)必須逐個列舉出來。(如果是無參函數(shù)就不用傳參數(shù))

function sum(num1, num2){
            return num1 + num2;
        }
        
        function callSum(num1, num2){
            return sum.call(this, num1, num2);
        }
        
        alert(callSum(10,10));   //20

傳遞參數(shù)并非兩個函數(shù)的真正用武之地吟吝,真正強(qiáng)大的地方是擴(kuò)充函數(shù)賴以運(yùn)行的作用域

window.color = "red";
        var o = { color: "blue" };
        
        function sayColor(){
            alert(this.color);
        }
        
        sayColor();            //red
        
        sayColor.call(this);   //red
        sayColor.call(window); //red
        sayColor.call(o);      //blue

如下代碼如果不用函數(shù)的方法來實(shí)現(xiàn)菱父。

window.color = "red";
        var o = { color: "blue" };
        
        function sayColor(){
            alert(this.color);
        }
        
        sayColor();     //red
        
        o.sayColor = sayColor;
        o.sayColor();   //blue

如果要輸出o對象里的color屬性值,必須把sayColor函數(shù)賦給對象o并調(diào)用 o.sayColor()時剑逃,this引用的對象為o

回歸要講的例子

當(dāng)一個函數(shù)被call和apply調(diào)用時浙宜,this的值就取傳入的對象的值。

var obj = {
            x: 10
        };
        var fn = function() {
            console.log(this); //Object { x: 10 }
            console.log(this.x); //10
        };
        fn.call(obj);

全局 & 調(diào)用普通函數(shù)

在全局環(huán)境下蛹磺,this永遠(yuǎn)是window粟瞬,這個應(yīng)該沒有非議。

console.log(this === window); //true

普通函數(shù)在調(diào)用時萤捆,其中的this也都是window裙品。

var x = 10;
        var fn = function() {
            console.log(this); //window
            console.log(this.x); //10
        }
        fn();

注意以下的情況

var obj = {
            x: 10,
            fn: function() {
                function f() {
                    console.log(this); //Window 
                    console.log(this.x); //undefined
                }
                f();
            }
        };
        obj.fn();

函數(shù)f雖然是在obj.fn內(nèi)部定義的俗批,但是它仍然是一個普通的函數(shù),this仍然指向window市怎。

總結(jié):this指向調(diào)用該函數(shù)的對象

構(gòu)造函數(shù)的prototype中岁忘,this代表著什么

function Fn() {
            this.name = "yzh";
            this.year = 1996;
        }
        Fn.prototype.getName = function() {
            console.log(this.name);
        }
        var f1 = new Fn();
        f1.getName(); //yzh

在Fn.prototype.getName函數(shù)中,this指向的是f1對象区匠。因此可以通過this.name獲取f1.name的值

bind()

bind()方法創(chuàng)建一個新的函數(shù), 當(dāng)被調(diào)用時干像,它的this關(guān)鍵字被設(shè)置為提供的值 ,在調(diào)用新函數(shù)時驰弄,提供任何一個給定的參數(shù)序列麻汰。

這個函數(shù)其實(shí)也很重要,只是當(dāng)時紅寶書也沒提及很多揩懒。

語法

fun.bind(thisArg[, arg1[, arg2[, ...]]])

參數(shù)

thisArg
當(dāng)綁定函數(shù)被調(diào)用時什乙,該參數(shù)會作為原函數(shù)運(yùn)行時的 this 指向挽封。當(dāng)使用new 操作符調(diào)用綁定函數(shù)時已球,該參數(shù)無效。

arg1, arg2, ...
當(dāng)綁定函數(shù)被調(diào)用時辅愿,這些參數(shù)將置于實(shí)參之前傳遞給被綁定的方法智亮。

返回值

返回由指定的this值和初始化參數(shù)改造的原函數(shù)拷貝

描述

bind() 函數(shù)會創(chuàng)建一個新函數(shù)(稱為綁定函數(shù)),新函數(shù)與被調(diào)函數(shù)(綁定函數(shù)的目標(biāo)函數(shù))具有相同的函數(shù)體(在 ECMAScript 5 規(guī)范中內(nèi)置的call屬性)点待。當(dāng)目標(biāo)函數(shù)被調(diào)用時 this 值綁定到 bind() 的第一個參數(shù)阔蛉,該參數(shù)不能被重寫。綁定函數(shù)被調(diào)用時癞埠,bind() 也接受預(yù)設(shè)的參數(shù)提供給原函數(shù)状原。一個綁定函數(shù)也能使用new操作符創(chuàng)建對象:這種行為就像把原函數(shù)當(dāng)成構(gòu)造器。提供的 this 值被忽略苗踪,同時調(diào)用時的參數(shù)被提供給模擬函數(shù)颠区。

示例

創(chuàng)建綁定函數(shù)

this.x = 9; 
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 返回 81

var retrieveX = module.getX;
retrieveX(); // 返回 9, 在這種情況下,"this"指向全局作用域

// 創(chuàng)建一個新函數(shù)通铲,將"this"綁定到module對象
// 新手可能會被全局的x變量和module里的屬性x所迷惑
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81

End

歡迎拍磚,有更多的好的例子毕莱,歡迎提出,文中有誤的地方也歡迎指正颅夺。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末朋截,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吧黄,更是在濱河造成了極大的恐慌部服,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拗慨,死亡現(xiàn)場離奇詭異廓八,居然都是意外死亡厦酬,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門瘫想,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仗阅,“玉大人,你說我怎么就攤上這事国夜〖踉耄” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵车吹,是天一觀的道長筹裕。 經(jīng)常有香客問我,道長窄驹,這世上最難降的妖魔是什么朝卒? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮乐埠,結(jié)果婚禮上抗斤,老公的妹妹穿的比我還像新娘。我一直安慰自己丈咐,他們只是感情好瑞眼,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著棵逊,像睡著了一般伤疙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辆影,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天徒像,我揣著相機(jī)與錄音,去河邊找鬼蛙讥。 笑死锯蛀,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的键菱。 我是一名探鬼主播谬墙,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼经备!你這毒婦竟也來了拭抬?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤侵蒙,失蹤者是張志新(化名)和其女友劉穎造虎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纷闺,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡算凿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年份蝴,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氓轰。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡婚夫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出署鸡,到底是詐尸還是另有隱情案糙,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布靴庆,位于F島的核電站时捌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏炉抒。R本人自食惡果不足惜奢讨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望焰薄。 院中可真熱鬧拿诸,春花似錦、人聲如沸蛤奥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凡桥。三九已至,卻和暖如春蚀同,著一層夾襖步出監(jiān)牢的瞬間缅刽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工蠢络, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衰猛,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓刹孔,卻偏偏與公主長得像啡省,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子髓霞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

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