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…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
