JavaScript 的函数方法apply、call和bind

JavaScript 函数类型

JavaScript 函数类型的介绍

在 JavaScript 中,所有 函数都是 对象。它们是 Function 类型的实例。因为函数是对象,所以它们与其他对象一样具有属性和方法。

函数属性

每个函数都有两个重要的属性:length 和 prototype。

  • length 属性确定函数声明中指定的命名参数数量。
  • prototype 属性引用实际的函数对象。

请看以下示例

JavaScript 复制代码
function add(x, y) {
    return x + y;
}

console.log(add.length); // 2
console.log(add.prototype); // Object{}Code language: JavaScript (javascript)

add() 函数接受两个参数 x 和 y。因此,length 属性返回 2。

new.target

通常,您可以像这样正常调用函数

JavaScript 复制代码
let result = add(10,20);
console.log(result); // 30Code language: JavaScript (javascript)

此外,您也可以使用 new 关键字作为构造函数调用函数

JavaScript 复制代码
let obj = new add(10,20);Code language: JavaScript (javascript)

ES6 引入了 new.target 伪属性,它允许您检测函数或构造函数是否使用 new 运算符调用。

如果函数是正常调用的,则 new.target 为 undefined。但是,如果使用 new 关键字作为构造函数调用函数,则 new.target 返回对构造函数的引用。

例如

JavaScript 复制代码
function add(x, y) {
  console.log(new.target);
  return x + y;
}

let result = add(10, 20);
let obj = new add(10, 20);
Code language: JavaScript (javascript)

输出

JavaScript 复制代码
undefined
[Function: add]Code language: JavaScript (javascript)

通过使用 new.target,您可以控制函数的调用方式。

例如,要阻止 add() 函数使用 new 关键字作为构造函数调用,您可以通过检查 new.target 来抛出错误,如下所示

JavaScript 复制代码
function add(x, y) {
  if (new.target) {
    throw 'The add function cannot be called as a constructor';
  }
  return x + y;
}

let obj = new add(10, 20);
console.log(obj);Code language: JavaScript (javascript)

函数方法:apply、call 和 bind

函数对象有三个重要的方法:apply()、call() 和 bind()。

apply() 和 call() 方法

apply() 和 call() 方法使用给定的 this 值和参数调用函数。

apply() 和 call() 之间的区别在于,您需要将参数作为类似数组的对象传递给 apply() 方法,而您将参数单独传递给 call() 函数。例如

JavaScript 复制代码
let cat = { type: 'Cat', sound: 'Meow' };
let dog = { type: 'Dog', sound: 'Woof' };

const say = function (message) {
  console.log(message);
  console.log(this.type + ' says ' + this.sound);
};

say.apply(cat, ['What does a cat say?']);
say.apply(dog, ['What does a dog say?']);Code language: JavaScript (javascript)

输出

JavaScript 复制代码
What does a cat sound?
Cat says Meow
What does a dog sound?
Dog says Woof

在此示例中

首先,声明两个具有两个属性的对象 cat 和 dog

JavaScript 复制代码
let cat = { type: 'Cat', sound: 'Meow' };
let dog = { type: 'Dog', sound: 'Woof' };Code language: JavaScript (javascript)

其次,定义接受一个参数的 say() 函数

JavaScript 复制代码
const say = function (message) {
  console.log(message);
  console.log(this.type + ' says ' + this.sound);
};Code language: JavaScript (javascript)

第三,通过 apply() 方法调用 say() 函数

JavaScript 复制代码
say.apply(cat, ['What does a cat say?']);Code language: CSS (css)

在此示例中, apply() 方法的第一个参数是 cat 对象。因此,say() 函数中的 this 对象引用了 cat 对象。

第四,调用 say() 函数并传递 dog 对象

JavaScript 复制代码
say.apply(dog, ['What does a dog say?']);Code language: CSS (css)

在此示例中,say() 函数中的 this 引用了 dog 对象。

call() 方法类似于 apply() 方法,只是您传递给函数的参数方式不同。

JavaScript 复制代码
say.call(cat, 'What does a cat say?');
say.call(dog, 'What does a dog say?');Code language: JavaScript (javascript)

bind() 方法

bind() 方法创建一个新的函数实例,其 this 值绑定到您提供的对象。例如

首先,定义一个名为 car 的对象

JavaScript 复制代码
let car = {
    speed: 5,
    start: function() {
        console.log('Start with ' + this.speed + ' km/h');
    }
};
Code language: JavaScript (javascript)

然后,定义另一个名为 aircraft 的对象

JavaScript 复制代码
let aircraft = {
    speed: 10,
    fly: function() {
        console.log('Flying');
    }
};Code language: JavaScript (javascript)

飞机没有 start() 方法。要启动飞机,您可以使用 car 对象的 start() 方法的 bind() 方法

JavaScript 复制代码
let taxiing = car.start.bind(aircraft);Code language: JavaScript (javascript)

在此语句中,我们将 car 对象的 start() 方法内部的 this 值更改为 aircraft 对象。 bind() 方法返回一个新函数,该函数被分配给 taxiing 变量。

现在,您可以通过 taxiing 变量调用 start() 方法

JavaScript 复制代码
taxiing();

它将显示以下消息

JavaScript 复制代码
Start with 10 km/hCode language: JavaScript (javascript)

以下示例使用 call() 方法在 aircraft 对象上调用 start() 方法

JavaScript 复制代码
car.start.call(aircraft);Code language: CSS (css)

如您所见,bind() 方法创建一个新函数,您可以在以后执行该函数,而 call() 方法立即执行该函数。这是 bind() 和 call() 方法之间的主要区别。

从技术上讲,飞机对象通过 bind()、call() 或 apply() 方法借用了 car 对象的 start() 方法。

因此,bind()、call() 和 apply() 方法也称为借用函数。

总结

  • 所有函数都是 Function 类型的实例,它们是具有属性和方法的对象。
  • 函数有两个重要的属性:length 和 prototype。
  • 函数还有三个重要的方法:call()、apply() 和 bind()。
相关推荐
幻境如梦丶皆为虚1 小时前
从零写一个 DSH 插件:在左侧菜单栏加一个「测试」
开发语言·javascript·ecmascript
吹什么轩1 小时前
constexpr 完全指南:从 const 的两种含义,到编译期计算的四次演进
java·前端·javascript
程序员大阳3 小时前
副队长JavaScript教程(67)-Ajax初识:背景、历史与核心概念
javascript·ajax·同步·异步·概念·背景·来是
程序员大阳3 小时前
副队长JavaScript教程(70)-Ajax同源策略与跨域
javascript·ajax·同源策略·跨越·corp
普通人64 小时前
Web端3D模型加载实战指南_Vue3_uni-app_HTML
前端·javascript·uni-app·html
志尊宝4 小时前
AI原生前端开发(042):AI辅助的路由设计与优化
javascript·react.js·ai-native
Dxy123931021615 小时前
JS DES 加密详解
开发语言·javascript·arcgis
充值内卷15 小时前
我给桌面加了个鱼缸:C++ 写后端,WebView2 里养一座 Three.js 小岛
开发语言·javascript·c++
椒哥17 小时前
一天被问几十次"允许",我统计了 517 次,然后写了个插件
前端·javascript·github
kyriewen18 小时前
我测了 6 种防请求竞态的写法:只有 1 种真能打
前端·javascript·程序员