【JS】函数定义与调用方式-函数this指向问题-call-apply-bind方法使用与自定义

这篇博客详细介绍了JavaScript中函数的定义方式,包括函数声明式、函数表达式、构造函数式、箭头函数,并强调了箭头函数的this指向特点。接着,讲解了函数的调用方式,如普通函数、对象方法、构造函数等,并特别讨论了函数中的this指向问题。此外,文章深入探讨了如何通过call、apply和bind方法改变函数的this指向,分析了三者的异同,并给出了应用场景。最后,展示了自定义实现call、apply和bind方法的代码示例。
摘要由CSDN通过智能技术生成

1. 函数定义的几种方式

1.1 函数声明式

function fn(a, b) {
  return a + b;
}

1.2 函数表达式

let fun = function(a, b){
  return a + b;
}

1.3 构造函数式

let fun = new Function('a', 'b', 'return a + b')

1.4 箭头函数

let fn = (a, b) => {
	return a + b;
};

关于箭头函数的更多内容,请见【ES6】JavaScript函数-箭头函数-this指向-简写

1.5 注意点

所有函数都是 Function 的实例对象, 属于对象 instanceof Object
在这里插入图片描述

2. 函数调用的几种方式

2.1 普通函数

fun()
fun.call()

2.2 对象的方法

obj.fun()

2.3 构造函数

new Fun()

2.4 绑定事件函数

触发事件调用

btn.onclick = function(){}; // 点击按钮调用

2.5 定时器函数

定时器到达指定时间自动调用

setInterval(function(){}, 1000) // 定时器自动一秒钟调用一次

2.6 立即执行函数

自动自己调用

(function(){})()

3. 函数中this指向

根据调用方式不同,this的指向也不同,一般指向调用者

具体总结表格如下所示

调用方式this指向
普通函数调用window
构造函数调用实例对象, 原型对象里面的方法也指向实例对象
对象方法调用该方法所属对象
事件绑定方法绑定事件对象
定时器函数window
立即执行函数window

4. 改变函数的this指向

4.1 使用call方法

fun.call(thisArg, arg1, arg2, ...)

作用:1. 调用函数 2. 改变函数this指向

function add(a, b) {
  console.log(a + b)
}

let obj = {
  c: 520
}
add(1,2) // this指向window
add.call(obj, 1, 2) // this指向obj

应用

主要的作用是可以实现继承

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方法

fun.apply(thisArg, [argsArray])

作用:1. 调用函数 2. 改变函数this指向
但是他的参数必须是数组(伪数组)

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 借助数学内置对象求最大值

let arr = [1, 34, 556, 44, 23]
Math.max.apply(null, arr); // null 表示不需要改变this指向
Math.max.apply(Math, arr); // 不改变的话最好就指回去

4.3 使用bind方法

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

不会调用函数,但是可以改变函数内部this的指向
返回 由指定的 this 值和初始化参数改造的原函数拷贝

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指向

let btn = document.querySelector('button')
btn.onclick = function() {
  this.disabled = true
  setTimeout(function(){
    this.disabled = false;
  }.bind(this), 3000)
}

4.4 区别与联系

相同

都可以改变函数内部的this指向

区别

callapply 会调用函数, 并且改变函数内部this指向.
callapply 传递的参数不一样, call 传递参数 arg1, arg2...形式 apply 必须数组形式[args]
bind 不会调用函数, 可以改变函数内部this指向.

主要应用场景

call 经常做继承.
apply 经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值
bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向

5. 自定义call、apply、bind方法

最后我们自己定义一下这三个方法。

call.js

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

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

import call from './call.js'

export default function bind(Fn, obj, ...args) {
  // 返回一个新的函数
  return function (...args2) {
    // 执行 call 函数、
    return call(Fn, obj, ...args, ...args2);
  };
}

测试

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));

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值