Lily 對(duì) Lucy說Hello
const lily= {
name: 'Lily',
sayHello(helloWord, other){
console.log(`${this.name} say ${helloWord} to ${other}`)
}
}
lily.sayHello("hello", "Lucy")
// Lily say Hello to Lucy
那換做其他對(duì)象怎么復(fù)用sayHello方法呢
const jack = {
name:'Jack'
}
lily.sayHello.call(jack, 'hello', 'Lilei')
// Jack say Hello to Lilei
lily.sayHello.apply(jack,[ 'hello', 'Lilei'])
// Jack say Hello to Lilei
let say2 = lily.sayHello.bind(jack,'hello')
say2('Lilei')
// Jack say Hello to Lilei
say2('David')
// Jack say Hello to David
下面實(shí)現(xiàn)call、 apply、bind的方法
Function.prototype.myCall = function(target,...args){
target = target || window
//定義一個(gè)不會(huì)重復(fù)的key,作為目標(biāo)對(duì)象target的屬性key
const funKey= Symbol()
//this即被調(diào)用的函數(shù)或?qū)ο螅瑢his變成目標(biāo)對(duì)象target屬性key的屬性值
target[funKey] = this
const res = target[funKey](...args)
delete target[funKey] // 執(zhí)行完借用的函數(shù)后,刪除掉
return res
}
// 區(qū)別就是這里第二個(gè)參數(shù)直接就是個(gè)數(shù)組
Function.prototype.myApply = function(target,args){
target = target || window
const funKey= Symbol()
target[funKey] = this
const res = target[funKey](...args)
delete target[funKey]
return res
}
// bind返回的是個(gè)函數(shù),需要執(zhí)行
Function.prototype.myBind = function (target,...outArgs) {
target = target || {}
const funKey = Symbol()
target[funKey] = this
return function (...innerArgs) { // 返回一個(gè)函數(shù)
const res = target[funKey](...outArgs, ...innerArgs)
//不能刪除,閉包函數(shù)(偏函數(shù))
// delete target[funKey]
return res
}
}
從上面的myBind的實(shí)現(xiàn)看;bind涉及到閉包,下面說下閉包、偏函數(shù)、柯里化
轉(zhuǎn)自: JS閉包應(yīng)用-私有變量、柯里化、偏函數(shù)@ Peterer~王勇
什么是閉包?
function generate() {
const a = 1;
//注意需要return內(nèi)部函數(shù),才回形成閉包
return function () {
// a這個(gè)變量不在當(dāng)前作用域,于是它是一個(gè)自由變量。
// 引用了自由變量的函數(shù)稱為閉包。
console.log(a++);
};
}
generate作為高階函數(shù)返回了一個(gè)新的函數(shù),該函數(shù)引用了外部作用域中的變量a,于是該函數(shù)稱為閉包函數(shù)。
- 閉包就是:引用了自由變量的函數(shù)。
- 自由變量:指在當(dāng)前作用域引用但既沒有定義在當(dāng)前作用域也未定義在全局作用域,而是定義在外層的局部作用域中的變量。
所以在此明確幾個(gè)關(guān)于閉包的要點(diǎn):
- 閉包必然是定義在一個(gè)函數(shù)內(nèi)部的,因?yàn)榫植孔饔糜蛑淮嬗诤瘮?shù)內(nèi)。
- 局部作用域的變量無法直接從外部訪問,只能通過作用域鏈訪問,所以閉包是訪問局部變量的橋梁。
- 閉包造成的直接結(jié)果是自由變量不被垃圾回收,所以自由變量可以緩存一些信息。
閉包的典型應(yīng)用場(chǎng)景有兩個(gè):
- 設(shè)置私有變量(基于局部變量的不可訪問性)
- 柯里化和偏函數(shù)(基于自由變量的不回收性)
私有變量就是那些函數(shù)可以調(diào)用但是外部無法直接獲取的變量。比如下面這個(gè)場(chǎng)景:
function User() {
// 這里的_password承擔(dān)著私有變量的作用
let _password;
return class User {
constructor(username, password) {
this.username = username;
// 使用自由變量保存密碼
_password = password;
}
login() {
console.log(this.username, _password);
}
};
}
const user = new (User())("diana", "password");
user.login();
- 我們希望隱藏用戶的密碼,只允許內(nèi)部訪問,此時(shí)就可以使用自由變量作為“私有變量”,返回一個(gè)閉包進(jìn)行訪問。
- 局部變量的外部不可訪問性是關(guān)鍵,本質(zhì)上這一切都來自于JS使用的詞法作用域模型,變量只能從內(nèi)向外單向查找。
柯里化是一種操作技巧,在編程中指的是:將接受n個(gè)參數(shù)的單個(gè)函數(shù)轉(zhuǎn)換為接受單個(gè)參數(shù)的n個(gè)函數(shù)。比如下面這個(gè)場(chǎng)景:
function info(country, province, city) {
console.log(country + "-" + province + "-" + city);
}
我們想要打印城市信息,對(duì)于某個(gè)省的城市我們需要重復(fù)的輸入country,province這兩個(gè)字段,此時(shí)我們可以對(duì)該函數(shù)進(jìn)行柯里化改造:
function info(country) {
return function (province) {
return function (city) {
console.log(country + "-" + province + "-" + city);
};
};
}
const province = info("中國")("浙江省");
province("杭州市");
province("溫州市");
- 我們將接受三個(gè)參數(shù)
country,province,city的函數(shù)轉(zhuǎn)換為三個(gè)只接受單個(gè)參數(shù)的函數(shù),然后根據(jù)需要隨時(shí)生成一個(gè)已經(jīng)內(nèi)置”部分參數(shù)“的函數(shù)。 - 這么做最大的好處是提高了代碼的復(fù)用性,我們可以提前緩存一些參數(shù),避免重復(fù)輸入。
偏函數(shù)也是一種操作技巧,在編程中指的是:將接受n個(gè)參數(shù)的單個(gè)函數(shù)任意固定a個(gè)參數(shù),返回接受剩余n-a個(gè)參數(shù)的函數(shù)。
偏函數(shù)和柯里化屬于一類操作,區(qū)別在于:
- 柯里化強(qiáng)調(diào)函數(shù)只能接受“單參數(shù)”,有n個(gè)參數(shù)就要拆解為n個(gè)單參數(shù)函數(shù);
- 偏函數(shù)更加“隨意”,將接受n個(gè)參數(shù)的函數(shù)一分為二,任意固定一個(gè)或多個(gè)參數(shù)。
上面的例子如果使用偏函數(shù):
function info(country) {
return function (province, city) {
console.log(country + "-" + province + "-" + city);
};
}
info("中國")("浙江省", "杭州市");
info("中國")("浙江省", "溫州市");
柯里化和偏函數(shù)本質(zhì)沒什么區(qū)別,只是約束不同。能夠?qū)崿F(xiàn)這類操作的核心有兩點(diǎn):
- 在于“自由變量”的不回收性,由于垃圾回收不去銷毀閉包中引用的自由變量,我們才能緩存部分參數(shù);
- 在于JS使用靜態(tài)的詞法作用域,詞法作用域的劃分和查詢根據(jù)”代碼書寫“的位置來決定。
對(duì)this對(duì)象的理解
作者:CUGGZ
鏈接:https://juejin.cn/post/6941194115392634888
來源:稀土掘金
this 是執(zhí)行上下文中的一個(gè)屬性,它指向最后一次調(diào)用這個(gè)方法的對(duì)象。在實(shí)際開發(fā)中,this 的指向可以通過四種調(diào)用模式來判斷。
- 第一種是函數(shù)調(diào)用模式,當(dāng)一個(gè)函數(shù)不是一個(gè)對(duì)象的屬性時(shí),直接作為函數(shù)來調(diào)用時(shí),this 指向全局對(duì)象。
- 第二種是方法調(diào)用模式,如果一個(gè)函數(shù)作為一個(gè)對(duì)象的方法來調(diào)用時(shí),this 指向這個(gè)對(duì)象。
- 第三種是構(gòu)造器調(diào)用模式,如果一個(gè)函數(shù)用 new 調(diào)用時(shí),函數(shù)執(zhí)行前會(huì)新創(chuàng)建一個(gè)對(duì)象,this 指向這個(gè)新創(chuàng)建的對(duì)象。
- 第四種是 apply 、 call 和 bind 調(diào)用模式,這三個(gè)方法都可以顯示的指定調(diào)用函數(shù)的 this 指向。其中 apply 方法接收兩個(gè)參數(shù):一個(gè)是 this 綁定的對(duì)象,一個(gè)是參數(shù)數(shù)組。call 方法接收的參數(shù),第一個(gè)是 this 綁定的對(duì)象,后面的其余參數(shù)是傳入函數(shù)執(zhí)行的參數(shù)。也就是說,在使用 call() 方法時(shí),傳遞給函數(shù)的參數(shù)必須逐個(gè)列舉出來。bind 方法通過傳入一個(gè)對(duì)象,返回一個(gè) this 綁定了傳入對(duì)象的新函數(shù)。這個(gè)函數(shù)的 this 指向除了使用 new 時(shí)會(huì)被改變,其他情況下都不會(huì)改變。
這四種方式,使用構(gòu)造器調(diào)用模式的優(yōu)先級(jí)最高,然后是 apply、call 和 bind 調(diào)用模式,然后是方法調(diào)用模式,然后是函數(shù)調(diào)用模式。