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…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...