【JS】JavaScript基礎知識自我檢查大過關(第三關)函式定義與呼叫
theme: fancy highlight: a11y-dark
嗨!~ 大家好,我是YK菌 🐷 ,一個微系前端 ✨,愛思考,愛總結,愛記錄,愛分享 🏹,歡迎關注我呀 😘 ~ [微訊號:
yk2012yk2012
,微信公眾號:ykyk2012
]
「這是我參與11月更文挑戰的第28天,活動詳情檢視:2021最後一次更文挑戰」
1. 函式定義的幾種方式
1.1 函式宣告式
javascript
function fn(a, b) {
return a + b;
}
1.2 函式表示式
javascript
let fun = function(a, b){
return a + b;
}
1.3 建構函式式
javascript
let fun = new Function('a', 'b', 'return a + b')
1.4 箭頭函式
javascript
let fn = (a, b) => {
return a + b;
};
關於箭頭函式的更多內容,請見【ES6】JavaScript函式-箭頭函式-this指向-簡寫
1.5 注意點
所有函式都是 Function
的例項物件, 屬於物件 instanceof Object
2. 函式呼叫的幾種方式
2.1 普通函式
javascript
fun()
fun.call()
2.2 物件的方法
javascript
obj.fun()
2.3 建構函式
javascript
new Fun()
2.4 繫結事件函式
觸發事件呼叫
javascript
btn.onclick = function(){}; // 點選按鈕呼叫
2.5 定時器函式
定時器到達指定時間自動呼叫
javascript
setInterval(function(){}, 1000) // 定時器自動一秒鐘呼叫一次
2.6 立即執行函式
自動自己呼叫
javascript
(function(){})()
3. 函式中this指向
根據呼叫方式不同,this的指向也不同,一般指向呼叫者
具體總結表格如下所示 |呼叫方式|this指向| |--|--| |普通函式呼叫|window| |建構函式呼叫|例項物件, 原型物件裡面的方法也指向例項物件| |物件方法呼叫|該方法所屬物件| |事件繫結方法|繫結事件物件| |定時器函式|window| |立即執行函式|window|
- 注意
在箭頭函式中,
this
是靜態的,this
始終指向函式宣告時所在作用域下的this的值 關於箭頭函式的更多內容,請見【ES6】JavaScript函式-箭頭函式-this指向-簡寫
4. 改變函式的this指向
4.1 使用call方法
javascript
fun.call(thisArg, arg1, arg2, ...)
作用:1. 呼叫函式 2. 改變函式this指向
```javascript function add(a, b) { console.log(a + b) }
let obj = { c: 520 } add(1,2) // this指向window add.call(obj, 1, 2) // this指向obj ```
應用
主要的作用是可以實現繼承
```javascript function Father(uname, age, sex) { this.uname = uname this.age = age this.sex = sex }
function Son(uname, age, sex){ Father.call(this, uname, age, sex) }
let son = new Son('YK菌', 18, '男') console.log(son) // Son {uname: "YK菌", age: 18, sex: "男"} ```
4.2 使用apply方法
javascript
fun.apply(thisArg, [argsArray])
作用:1. 呼叫函式 2. 改變函式this指向 但是他的引數必須是陣列(偽陣列) ```javascript function add(a, b) { console.log(a + b) }
let obj = { c: 520 } add(1,2) // this指向window add.call(obj, [1, 2]) // this指向obj ```
應用
可以利用apply 藉助數學內建物件求最大值
javascript
let arr = [1, 34, 556, 44, 23]
Math.max.apply(null, arr); // null 表示不需要改變this指向
Math.max.apply(Math, arr); // 不改變的話最好就指回去
4.3 使用bind方法
javascript
fun.bind(thisArg, arg1, arg2, ...)
不會呼叫函式,但是可以改變函式內部this的指向
返回 由指定的 this
值和初始化引數改造的原函式拷貝
```javascript function add(a, b) { console.log(a + b) }
let obj = { c: 520 } add(1,2) // this指向window let f = add.bind(obj, 1, 2) // this指向obj, 不會呼叫 f() // 呼叫函式 this指向obj ```
應用
改變定時器內部的this
指向
javascript
let btn = document.querySelector('button')
btn.onclick = function() {
this.disabled = true
setTimeout(function(){
this.disabled = false;
}.bind(this), 3000)
}
4.4 區別與聯絡
相同
都可以改變函式內部的this
指向
區別
call
和 apply
會呼叫函式, 並且改變函式內部this指向.
call
和 apply
傳遞的引數不一樣, call
傳遞引數 arg1, arg2...
形式 apply
必須陣列形式[args]
bind
不會呼叫函式, 可以改變函式內部this
指向.
主要應用場景
call
經常做繼承.
apply
經常跟陣列有關係. 比如藉助於數學物件實現陣列最大值最小值
bind
不呼叫函式,但是還想改變this指向. 比如改變定時器內部的this
指向
5. 自定義call、apply、bind方法
最後我們自己定義一下這三個方法。
call.js
javascript
export default function call(Fn, obj, ...args) {
if (obj === undefined || obj === null) {
// 表示全域性物件(ES11新增特性)
obj = globalThis;
}
// 為 obj 新增臨時的方法
obj.temp = Fn;
// 呼叫 temp 方法
let result = obj.temp(...args);
// 刪除tempfangfa
delete obj.temp;
// 返回執行結果
return result;
}
apply.js
```javascript export default function apply(Fn, obj, arr) { if (obj === undefined || obj === null) { obj = globalThis; } // 為obj新增臨時方法 obj.temp = Fn; // 執行方法 let result = obj.temp(...arr); // 刪除臨時屬性 delete obj.temp; // 返回結果 return result; }
```
bind.js
```javascript import call from './call.js'
export default function bind(Fn, obj, ...args) { // 返回一個新的函式 return function (...args2) { // 執行 call 函式、 return call(Fn, obj, ...args, ...args2); }; }
```
測試
```javascript import call from "./function/call"; import apply from "./function/apply"; import bind from "./function/bind";
console.log("*test call *");
function add(a, b) { console.log(this); return a + b + this.c; } let obj = { c: 521, }; window.c = 1314;
console.log(call(add, obj, 10, 20)) console.log(call(add, null, 30, 40))
console.log(obj) console.log("*test apply*"); console.log(apply(add, obj, [10, 20])) console.log(apply(add, null, [30, 40]))
console.log(obj) console.log("*test bind*"); let fn = bind(add, obj, 10, 20); console.log(fn());
let fn2 = bind(add, obj);
console.log(fn2(10, 20));
```
最後,歡迎關注我的專欄,和YK菌做好朋友
- 從校園到職場 | YK菌的2022年中總結
- 【青訓營】月影老師告訴我寫好JavaScript的三大原則——元件封裝
- 【青訓營】月影老師告訴我寫好JavaScript原則與技巧大總結
- 2022屆秋招,從被拒到上岸 | 談談YK菌在2021年的經歷與收穫
- 【TS】快速上手(四)配置選項 - 編譯選項compilerOptions
- 【LeetCode】圖解反轉連結串列 - 迭代 - 遞迴
- 【LeetCode】最大子序和從O(N^3)到O(N) - 暴力初探 - 分而治之 - 線上處理
- 【JS】JavaScript基礎知識自我檢查大過關(第三關)函式定義與呼叫
- 【Vue】高階系列(六)Vue-cli配置代理 -demo3-GitHub使用者查詢-axios
- 【Vue】高階系列(五)元件間通訊
- 【Vue】高階系列(四)Vue模組化實戰-demo2-任務清單todoList
- 【TS】快速上手(二)型別宣告
- 【Vue】高階系列(三)Vue模組化實戰-demo1-動態評價頁面
- 【Vue】高階系列(二)Vue相關小知識
- 【Vue】高階系列(一)Vue元件定義與使用 - 非單檔案元件 - 單檔案元件 - VueComponent
- 【Vue】基礎系列(十一)Vue指令-常用內建指令-自定義指令-全域性指令-區域性指令
- 【Vue】基礎系列(九)動畫與過渡-trasition-enter-leave
- 【Vue】基礎系列(八)生命週期 - 初始化顯示 - 更新狀態 - 死亡狀態 - 父子元件
- 【Vue】基礎系列(七)v-model - 自動收集資料 - 表單資料自動更新
- 【Vue】基礎系列(六)事件處理 - 繫結監聽 - 事件修飾符 - 按鍵修飾符