JavaScript之applye、bind和call方法详解
Question
-
Q1 apply()、bind()和call()方法的区别在哪?
-
Q2 apply()和call()的应用场景
-
Q3 apply()、bind()和call()方法手写实现逻辑
来源
继承自Function.prototype,属于实例方法
console.log(Function.prototype.hasOwnProperty('call')) //true
console.log(Function.prototype.hasOwnProperty('apply')) //true
console.log(Function.prototype.hasOwnProperty('bind')) //true
定义
apply()、bind()和call()方法的作用都是改变this指向,可以指定该函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。
一般用法
// 限浏览器Console执行
var year = 2022 // 不能用let
function getDate(month, day) {
console.log(this.year + '-' + month + '-' + day)
}
let obj = { year: 2023 }
getDate.call(this, 1, 1) //2022-1-1 this|null|undefined均可
getDate.call(obj, 1, 1) //2023-1-1
getDate.apply(obj, [1, 1]) //2023-1-1
getDate.bind(obj)(1, 1) //2023-1-1
区别
-
apply()的参数为数组
-
apply()和call()立即执行,bind()返回新函数,并非立即执行
apply()
找出最大值和最小值
var arr = [5, 6, 2, 3, 7]
console.log(Math.max.apply(null, arr))
console.log(Math.min.apply(null, arr))
将数组的空元素变为undefined
// 空元素与undefined的差别在于,数组的forEach方法会跳过空元素,但是不会跳过undefined和null。因此,遍历内部元素的时候,会得到不同的结果
console.log(Array.apply(null, [1, , 3])) // [1, undefined, 3]
转换类似数组的对象
function keith(a, b, c) {
return arguments
}
console.log(Array.prototype.slice.apply(keith(2, 3, 4))) //[2,3,4]
console.log(Array.prototype.slice.call(keith(2, 3, 4))) //[2,3,4]
bind()
var func = {
a: 1,
count: function () {
console.log(this.a++)
}
}
var ff = func.count.bind(func)
ff()
call()
调用对象的原生方法
var obj = {}
console.log(obj.hasOwnProperty('toString')) //false
obj.hasOwnProperty = function () {
return true
}
console.log(obj.hasOwnProperty('toString')) //true
console.log(Object.prototype.hasOwnProperty.call(obj, 'toString')) //false
调用父构造函数
function Product(name, price){
this.name = name
this.price = price
}
// 调用父构造函数的call方法来实现继承
function Food(name, price){
Product.call(this, name, price)
this.category = 'food'
}
function Toy(name, price){
Product.call(this, name, price)
this.category = 'toy'
}
var cheese = new Food('feta', 5)
var fun = new Toy('robot', 40)
console.log(cheese)
console.log(fun)
手写
apply()
/**
* 模拟 apply
* 调用一个具有给定 this 值的函数,以及以一个数组(或类数组对象)的形式提供的参数
* @param {object} ctx
* @param {} args
*/
Function.prototype.__apply = function (ctx, args) {
if (typeof this !== 'function') throw new TypeError('Error')
// 考虑 null 情况,参数默认赋值会无效
if (!ctx) ctx = window
// 将 this 函数保存在 ctx 上
ctx.fn = this
// 传参执行并保存返回值
const result = ctx.fn(...args)
// 删除 ctx 上的 fn
delete ctx.fn
return result
}
// ------------------------------ 测试 ------------------------------
const numbers = [5, 6, 2, 3, 7]
// Function.prototype.__apply()
console.log('Function.prototype.__apply()')
const max = Math.max.__apply(null, numbers)
console.log(max) // 7
// Function.prototype.apply()
console.log('Function.prototype.apply()')
const min = Math.min.apply(null, numbers)
console.log(min) // 2
bind()
/**
* 1. bind() 方法创建一个新的函数
* 2. 在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数
* 3. new 情况下忽略第一个参数
* 4. 其余参数将作为新函数的参数,供调用时使用
* @param {object} ctx
* @param {...any} args
* @returns {function} 返回一个原函数的拷贝,并拥有指定 this 值和初始参数
*/
Function.prototype.__bind = function (ctx, ...args) {
// 判断 this 是否为 function 类型
if (typeof this !== 'function') throw new TypeError('Error')
// 保存当前 this
const __this = this
return function F() {
return this instanceof F
? new __this(...args, ...arguments) // new
: __this.apply(ctx, [...args, ...arguments]) // 直接调用时绑定 this
}
}
// ------------------------------ 测试 ------------------------------
function print() {
console.log(this.name, ...arguments)
}
const obj = {
name: 'mxin',
}
// Function.prototype.__bind()
console.log('Function.prototype.__bind()')
// 直接调用,返回原函数拷贝,this 指向 obj
const F = print.__bind(obj, 26)
F(178) // mxin, 26, 178
// new 情况
const _obj = new F(145) // undefined, 26, 145
console.log(_obj) // print {}
// Function.prototype.bind()
console.log('Function.prototype.bind()')
const Fn = print.bind(obj, 26)
Fn(178) // mxin, 26, 178
const __obj = new Fn(145) // undefined, 26, 145
console.log(__obj) // print {}
call()
/**
* 模拟 call
* 使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数
* @param {object} ctx
* @param {...any} args
* @returns {any} 调用 this 的返回值,若无有返回值,则返回 undefined
*/
Function.prototype.__call = function (ctx, ...args) {
if (typeof this !== 'function') throw new TypeError('Error')
// 考虑 null 情况,参数默认赋值会无效
if (!ctx) ctx = window
// 将 this 函数保存在 ctx 上
ctx.fn = this
// 传参执行并保存返回值
const res = ctx.fn(...args)
// 删除 ctx 上的 fn
delete ctx.fn
return res
}
// ------------------------------ 测试 ------------------------------
function Product(name, price) {
this.name = name
this.price = price
}
// Function.prototype.__call()
console.log('Function.prototype.__call()')
function Food(name, price) {
Product.__call(this, name, price)
this.category = 'food'
}
const food = new Food('cheese', 5)
console.log(food)
// Food {name: "cheese", price: 5, category: "food"}
// category: "food"
// name: "cheese"
// price: 5
// __proto__:
// constructor: ƒ Food(name, price)
// __proto__: Object
// Function.prototype.call()
console.log('Function.prototype.call()')
function Toy(name, price) {
Product.call(this, name, price)
this.category = 'toy'
}
const toy = new Toy('car', 10)
console.log(toy)
// Toy {name: "car", price: 10, category: "toy"}
// category: "toy"
// name: "car"
// price: 10
// __proto__:
// constructor: ƒ Toy(name, price)
// __proto__: Object
本文由 mdnice 多平台发布
相关文章:
JavaScript之applye、bind和call方法详解
Question Q1 apply()、bind()和call()方法的区别在哪? Q2 apply()和call()的应用场景 Q3 apply()、bind()和call()方法手写实现逻辑 来源 继承自Function.prototype,属于实例方法 console.log(Function.prototype.hasOwnProperty(call)) //trueconsole.l…...

Docker,anaconda环境的部署与迁移
功能上线将提上日程,但是如何将我windows环境下的程序放到linux服务器的测试环境跑通呢?这是我这整个清明假期将要解决的一件事,最蠢的办法就是看自己的环境下有哪些依赖,如何到服务器上一个一个下,但是首先这个方法很…...
【大数据运维】Hbase shell 常见操作
文章目录 一. DDL1. 表的DDL1.1. 创建表1.2. 删除表 2. 列族的DDL2.1. 增加一个列簇2.2. 删除列族2.3. 修改列族版本(ing) 二. DML1. 插入与更新数据2. 删除数据3. 清空表 三. DQL1. scan:查一批数据1.1. 查询全部1.2. 过滤rowkey1.3. 过滤列…...

LeetCode-217存在重复的元素
217 存在重复的元素 给定一个整数数组,判断是否存在重复元素。 如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。 JavaScript的 Array 对象是用于构造数组的全局对象,数组是类似…...

基于两个单片机串行通信的电子密码锁设计
1.功能 电子号码锁在实际应用中应该有两部分,一部分在外部,有键盘部分和密码显示;另一部分内部,设置密码、显示密码。使用单片机自身带有的串口可以很方便的实现单片机之间的通信,使输入的密码值传送到主机检验是否是…...
产品经理功法修炼(3)之产品设计
点击下载《产品经理功法修炼(3)之产品设计》 1. 前言 产品经理的能力修炼并非局限于某一技能的速成,而是需要全面参与到产品的整个生命周期中,通过不断的实践来逐步提升自己的各项能力。尽管在企业的日常运作中,我们不可能身兼数职去扮演每一个角色,但作为产品的核心负…...

Qt 的发展历史、现状与启示
Qt 最早在1991年由挪威的两位程序员 Eirik Chambe-Eng 和 Haavard Nord 开发,他们在1994年创立 Trolltech 公司(奇趣科技)正式经营软件业务。Qt 的第一个公众预览版于1995年面世,之后在2008年被诺基亚收购;2011年到201…...

Quiet-STaR:让语言模型在“说话”前思考
大型语言模型(llm)已经变得越来越复杂,能够根据各种提示和问题生成人类质量的文本。但是他们的推理能力让仍然是个问题,与人类不同LLM经常在推理中涉及的隐含步骤中挣扎,这回导致输出可能在事实上不正确或缺乏逻辑。 考虑以下场景:正在阅读一…...
【Kotlin】匿名类和伴生类
1 匿名类 1)无继承 fun main() {var obj object {var name: String "zhang"override fun toString(): String {return name}}println(obj) // zhang } 2)有继承 fun main() {var obj object: People {var name: String "zhang"…...
【机器学习算法介绍】(3)决策树
决策树是一种常见的机器学习算法,用于分类和回归任务。它模拟了人类决策过程,通过一系列的问题来引导决策。决策树的构建涉及三个主要步骤:特征选择、树的构建和树的剪枝。 1. 特征选择 特征选择是决策树构建过程中的第一步,目的…...
算法之查找
1、顺序查找: package com.arithmetic.search; //顺序查找 //sequentialSearch 方法接收一个整数数组和一个目标元素作为参数,并使用顺序查找的方式在数组中查找目标元素。 //它通过循环遍历数组元素,逐个与目标元素比较,如果找到…...

LInux脚本学习
1.注释 #单行注释 以 # 字符开头就是单行注释 当然第一行除外,比较特殊 2.多行注释 3.Shell文件的作用 Shell文件就是linux命令集 4.sh脚本的执行方式 bash xxx.sh 5.新建的文件会没有执行权限 #为文件赋予执行权限 chmod ux xxx.sh 6.编写规范 #!/bin/bash #…...
JavaWeb基础(计网 socket 数据库 JDBC lombok Mybatis JUnit Maven)
本文用于检验学习效果,忘记知识就去文末的链接复习 1. 网络基础 1.1 计网基础 区分设备:IP地址 区分网络:网络地址 网络互联:路由器 主机上进程间通信:端口 http是常用的协议,基于TCP协议 TCP VS U…...

【HBase】
什么是HBase HBase是Google Bigtable的开源实现,类似Google Bigtable利用GFS作为其文件存储系统,HBase利用Hadoop HDFS作为其文件存储系统;Google运行MapReduce来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据。 访问层次(数据…...
Vue3:使用Pinia存储、读取、修改数据
一、存储数据 Pinia插件中,存储数据的配置项是state count.ts import {defineStore} from piniaexport const useCountStore defineStore(count,{// 真正存储数据的地方state(){return {sum:6}} })loveTalk.ts import {defineStore} from piniaexport const use…...

基于 Quartz.NET 可视化任务调度平台 QuartzUI
一、简介 QuartzUI 是基于 Quartz.NET3.0 的定时任务 Web 可视化管理,Docker 打包开箱即用、内置 SQLite 持久化、语言无关、业务代码零污染、支持 RESTful 风格接口、傻瓜式配置、异常请求邮件通知等。 二、部署 QuartzUI 从 2022 年到现在没有提交记录…...

前端三剑客 —— CSS (第三节)
目录 上节回顾: 1.CSS使用有以下几种样式; 2.选择器 1.基本选择器 2.包含选择器 3.属性选择器 [] 4.伪类选择器 : 5.伪元素选择器 ::before :after 3.常见样式的使用 常见样式参考表 一些特殊样式 媒体查询 自定义字体 变换效果 translate&…...
C# 系统学习(异步编程)
在C#中,异步编程是一种优化程序性能的关键技术,特别是在处理I/O密集型操作(如网络请求、数据库查询、文件读写等)时,能够有效避免由于长时间等待而导致的线程阻塞,从而提高应用的响应速度和资源利用率。asy…...

前端工程师————CSS学习
选择器分类 选择器分为基础选择器和复合选择器 基础选择器包括:标签选择器,类选择器,id选择器,通配符选择器标签选择器 类选择器 语法:.类名{属性1: 属性值;} 类名可以随便起 多类名使用方式&am…...

C# 登录界面代码
背景 MVVM 是一种软件架构模式,用于创建用户界面。它将用户界面(View)、业务逻辑(ViewModel)和数据模型(Model)分离开来,以提高代码的可维护性和可测试性。 MainWindow 类是 View&a…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...