亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

為什么要改變this指向?

我們知道bind,call,Apply的作用都是用來(lái)改變this指向的,那為什么要改變this指向呢?請(qǐng)看下面的例子:

var name="lucy";
let obj={
 name:"martin",
 say:function () {
 console.log(this.name);
 }
};
obj.say(); //martin,this指向obj對(duì)象
setTimeout(obj.say,0); //lucy,this指向window對(duì)象

可以觀察到,正常情況下 say 方法中的 this 是指向調(diào)用它的 obj 對(duì)象的,而定時(shí)器 setTimeout 中的 say 方法中的 this 是指向window對(duì)象的(在瀏覽器中),這是因?yàn)?say 方法在定時(shí)器中是作為回調(diào)函數(shù)來(lái)執(zhí)行的,因此回到主棧執(zhí)行時(shí)是在全局執(zhí)行上下文的環(huán)境中執(zhí)行的,但我們需要的是 say 方法中 this 指向obj對(duì)象,因此我們需要修改 this 的指向。

作用

call、apply、bind作用是改變函數(shù)執(zhí)行時(shí)的上下文,簡(jiǎn)而言之就是改變函數(shù)運(yùn)行時(shí)的this指向

那么什么情況下需要改變this的指向呢?下面舉個(gè)例子

var name = "lucy";
var obj = {
    name: "martin",
    say: function () {
        console.log(this.name);
    }
};
obj.say(); // martin,this 指向 obj 對(duì)象
setTimeout(obj.say,0); // lucy,this 指向 window 對(duì)象

從上面可以看到,正常情況say方法輸出martin

但是我們把say放在setTimeout方法中,在定時(shí)器中是作為回調(diào)函數(shù)來(lái)執(zhí)行的,因此回到主棧執(zhí)行時(shí)是在全局執(zhí)行上下文的環(huán)境中執(zhí)行的,這時(shí)候this指向window,所以輸出lucy

我們實(shí)際需要的是this指向obj對(duì)象,這時(shí)候就需要該改變this指向了

setTimeout(obj.say.bind(obj),0); //martin,this指向obj對(duì)象

區(qū)別

下面再來(lái)看看apply、call、bind的使用

apply

apply接受兩個(gè)參數(shù),第一個(gè)參數(shù)是this的指向,第二個(gè)參數(shù)是函數(shù)接受的參數(shù),以數(shù)組的形式傳入,且當(dāng)?shù)谝粋€(gè)參數(shù)為null、undefined的時(shí)候,默認(rèn)指向window(在瀏覽器中),使用apply方法改變this指向后原函數(shù)會(huì)立即執(zhí)行,且此方法只是臨時(shí)改變thi指向一次。

先上一個(gè)例子,比較好理解

var foo = {
	value: 1
};

function bar(name, age) {
	console.log(name)
	console.log(age)
	console.log(this.value);
}

bar.apply(foo, ['kevin', 18]);
// kevin
// 18
// 1

值得注意的事情是,當(dāng)使用apply()方法時(shí),控制臺(tái)會(huì)打印出我們所希望打印的內(nèi)容,也就是bar函數(shù)執(zhí)行了,在改變其this指向后,執(zhí)行改變后的函數(shù),關(guān)于這一點(diǎn),call()方法的執(zhí)行也是一樣的。

顯然我們傳入的數(shù)組,會(huì)被正確解析為bar中所需要的參數(shù)

日常用法:改變this指向

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"張三"
}

fn.apply(obj,[1,2]); // this會(huì)變成傳入的obj,傳入的參數(shù)必須是一個(gè)數(shù)組;
fn(1,2) // this指向window

當(dāng)?shù)谝粋€(gè)參數(shù)為null、undefined的時(shí)候,默認(rèn)指向window(在瀏覽器中)

fn.apply(null,[1,2]); // this指向window
fn.apply(undefined,[1,2]); // this指向window

call

call方法的第一個(gè)參數(shù)也是this的指向,后面?zhèn)魅氲氖且粋€(gè)參數(shù)列表

跟apply一樣,改變this指向后原函數(shù)會(huì)立即執(zhí)行,且此方法只是臨時(shí)改變this指向一次

調(diào)用call的方式如下

var foo = {
    value: 1
};

function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}

bar.call(foo, 'kevin', 18);
// kevin
// 18
// 1

有了call為什么還要apply呢,經(jīng)過(guò)一番查閱后,了解到使用call的速度比apply快,那疑惑就更嚴(yán)重了,apply還有存在的意義嗎?我們不妨假設(shè)當(dāng)需要傳入的參數(shù)很多時(shí),一般都是存放在數(shù)組中,如果只有call的話,就需要我們對(duì)數(shù)組做一些處理,轉(zhuǎn)換成參數(shù)列表的形式,但是使用apply的話就減輕了工作量,可以這樣認(rèn)為吧,apply時(shí)call的語(yǔ)法糖。(為什么參數(shù)多的時(shí)候會(huì)存放在數(shù)組里面捏?本孩認(rèn)為,數(shù)組可以被認(rèn)為一個(gè)整體,不易出現(xiàn)丟參的情況,而且數(shù)組有長(zhǎng)度,可以輕而易舉的知道到底有多少個(gè)參數(shù))

 

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"張三"
}

fn.call(obj,1,2); // this會(huì)變成傳入的obj,傳入的參數(shù)必須是一個(gè)數(shù)組;
fn(1,2) // this指向window

同樣的,當(dāng)?shù)谝粋€(gè)參數(shù)為null、undefined的時(shí)候,默認(rèn)指向window(在瀏覽器中)

fn.call(null,[1,2]); // this指向window
fn.call(undefined,[1,2]); // this指向window

bind

bind方法和call很相似,第一參數(shù)也是this的指向,后面?zhèn)魅氲囊彩且粋€(gè)參數(shù)列表(但是這個(gè)參數(shù)列表可以分多次傳入)

改變this指向后不會(huì)立即執(zhí)行,而是返回一個(gè)永久改變this指向的函數(shù)

var foo = {
	value: 1
};

function bar(name, age) {
	console.log(name)
	console.log(age)
	console.log(this.value);
}

bar.bind(foo, 'kevin', 18);
// 沒(méi)有任何輸出

為什么會(huì)沒(méi)有輸出呢?上文已經(jīng)提到了,這就是和bind、call的區(qū)別了

bind不會(huì)執(zhí)行bar函數(shù),只是改變了其this指向,并且給它傳入了參數(shù),添加一行代碼呢?如下:

var foo = {
	value: 1
};

function bar(name, age) {
	console.log(name)
	console.log(age)
	console.log(this.value);
}

bar.bind(foo, 'kevin', 18);
bar();
// undefined
// undefined
// undefined

對(duì)的,你沒(méi)看錯(cuò),輸出了三個(gè)undefined,因?yàn)殡m然調(diào)用了bar(),但this指向了window且沒(méi)有傳入任何參數(shù),理所當(dāng)然都是undefined了,可見(jiàn)使用了bind后并不會(huì)改變?cè)瘮?shù),其實(shí)call和apply也都不會(huì)改變?cè)瓍?shù),也就是說(shuō)call和apply是一次性的,這里為什么我沒(méi)說(shuō)bind呢,因?yàn)樗麜?huì)返回一個(gè)函數(shù),如果我們保存這個(gè)函數(shù),它就不是一次性的了,如果再執(zhí)行這個(gè)函數(shù)就可以達(dá)到我們想要的效果了,注意:執(zhí)行apply和call時(shí),就如同執(zhí)行原函數(shù),返回值和原函數(shù)相同,如果原函數(shù)不返回值,則apply和call也不會(huì)返回任何值!

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"張三"
}

const bindFn = fn.bind(obj); // this 也會(huì)變成傳入的obj ,bind不是立即執(zhí)行需要執(zhí)行一次
bindFn(1,2) // this指向obj
fn(1,2) // this指向window

小結(jié)

從上面可以看到,apply、call、bind三者的區(qū)別在于:

  • 三者都可以改變函數(shù)的this對(duì)象指向
  • 三者第一個(gè)參數(shù)都是this要指向的對(duì)象,如果如果沒(méi)有這個(gè)參數(shù)或參數(shù)為undefined或null,則默認(rèn)指向全局window
  • 三者都可以傳參,但是apply是數(shù)組,而call是參數(shù)列表,且apply和call是一次性傳入?yún)?shù),而bind可以分為多次傳入
  • bind是返回綁定this之后的函數(shù),apply、call 則是立即執(zhí)行

實(shí)現(xiàn)

實(shí)現(xiàn)bind的步驟,我們可以分解成為三部分:

  • 修改this指向
  • 動(dòng)態(tài)傳遞參數(shù)
// 方式一:只在bind中傳遞函數(shù)參數(shù)
fn.bind(obj,1,2)()

// 方式二:在bind中傳遞函數(shù)參數(shù),也在返回函數(shù)中傳遞參數(shù)
fn.bind(obj,1)(2)
  • 兼容new關(guān)鍵字

整體實(shí)現(xiàn)代碼如下:

Function.prototype.myBind = function (context) {
    // 判斷調(diào)用對(duì)象是否為函數(shù)
    if (typeof this !== "function") {
        throw new TypeError("Error");
    }

    // 獲取參數(shù)
    const args = [...arguments].slice(1),
          fn = this;

    return function Fn() {

        // 根據(jù)調(diào)用方式,傳入不同綁定值
        return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments)); 
    }
}

給大家分享我收集整理的各種學(xué)習(xí)資料,前端小白交學(xué)習(xí)流程,入門教程等回答-下面是學(xué)習(xí)資料參考。

分享到:
標(biāo)簽:bind
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定