当前位置: 首页 > news >正文

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 年到现在没有提交记录&#xf…...

前端三剑客 —— 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…...

点云的Python均值采样

一、代码 Python import numpy as np import open3d as o3ddef mean_sampling(point_cloud, num_samples=None, depth=None, method=knn, k=10):"""对点云进行均值下采样。:param point_cloud: Open3D PointCloud对象:param num_samples: (仅当method=knn时使…...

xss-labs 11-13通关记录

前言 最近复习xss知识&#xff0c;整理一下xss的绕过思路。 level11 观察测试: 1.四个隐藏参数标签 2.全部get传参一遍发现t_sort可赋值&#xff0c;使用的是get传参 3.针对t_sort测试过滤的字符 t_sort< > & ; " 检测到他除了<>,别的全部过滤。 因为…...

Unity类银河恶魔城学习记录12-2 p124 Character Stats UI源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI_Statslot.cs using System.Collections; using System.Collections.Gen…...

技术揭秘:如何打造完美互动的充电桩硬件与服务平台?

充电桩平台全套源码地址 https://gitee.com/chouleng/cdzkjjh.git 这张图像是一个系统或服务的架构图。以下是对图中各个部分的描述&#xff1a; 前端&#xff1a; 位于图像的顶部&#xff0c;颜色为浅绿色。用户服务端&#xff1a; 紧邻前端&#xff0c;颜色为淡黄色。设备服…...

【Django学习笔记(四)】JavaScript 语言介绍

JavaScript 语言介绍 前言正文1、JavaScript 小案例2、代码位置2.1 在当前 HTML 文件中2.2 在其他 js 文件中 3、代码注释3.1 HTML的注释3.2 CSS的注释3.3 Javascript的注释 4、变量 & 输出4.1 字符串4.2 数组4.3 对象(python里的字典) 5、条件语句6、函数7、DOM7.1 根据 I…...

IO和NIO的主要区别在哪里?

Java 中的 IO&#xff08;输入/输出&#xff09;和 NIO&#xff08;新输入/输出&#xff09;都是处理输入和输出操作的方式&#xff0c;它们的主要区别在于如何处理数据的读写。 阻塞与非阻塞: IO是阻塞的&#xff0c;这意味着当一个线程调用read()或write()时&#xff0c;该线…...

爬虫部署平台crawlab使用说明

Crawlab 是一个基于 Go 语言的分布式网络爬虫管理平台&#xff0c;它支持 Python、Node.js、Jar、EXE 等多种类型的爬虫。 Crawlab 提供了一个可视化的界面&#xff0c;并且可以通过简单的配置来管理和监控爬虫程序。 以下是 Crawlab 的一些主要优点&#xff1a; 集中管理&am…...

uniapp uni.scss中使用@mixin混入,在文件引入@include 样式不生效 Error: Undefined mixin.(踩坑记录一)

问题&#xff1a; 在uni.scss文件定义mixin 2. 在vue文件引入: 3. 出现报错信息: 4. 问题思考&#xff1a; 是不是需要引入uni.scss &#xff1f; 答案不需要 uni.scss是一个特殊文件&#xff0c;在代码中无需 import 这个文件即可在scss代码中使用这里的样式变量。uni-app的…...

Redis的5大常见数据类型的用法

上一篇文章我们讲了Redis的10大应用场景&#xff0c;这一篇文章就针对Redis的常用数据结构进行一个说明&#xff0c;通过示例的形式演示每一种数据结构如何使用。 当涉及Redis的数据操作时&#xff0c;不同数据类型对应的不同数据结构&#xff0c;如下就对5大常用的数据类型进行…...

刘小光本就疑心赵本山与他媳妇李琳有染,赵本山为证实清白便想起蛋糕上的字,结果呢?

刘小光本就疑心赵本山与他媳妇李琳有染&#xff0c;赵本山为证实清白便想起蛋糕上的字&#xff0c;结果呢&#xff1f; ——小品《生日快乐》&#xff08;中5&#xff09;的台词 &#xff08;接上&#xff09; 赵本山&#xff1a;噢!对对!那谁&#xff0c;老四&#xff0c;是…...

金坛网站建设哪家好/个人网站设计

关于推送的集成请参考这篇文章&#xff0c;本篇文章将引导你集成统计功能&#xff0c;只需要简单的三个步骤就可以集成统计功能。第一步 安装在你的项目路径下执行命令&#xff1a;npm install janalytics-react-native --savenpm install jcore-react-native --savereact-nati…...

网站开发环境是什么/独立站seo优化

一、关于版本控制 版本控制是一种记录若干文件内容变化&#xff0c;以便将来查阅特定版本修订情况的系统。我们通常仅对保存着软件源代码的文本文件做版本控制&#xff0c;但实际上&#xff0c;你可以对任何类型的文件进行版本控制。 采用版本控制系统&#xff08;VCS&#xff…...

网站建设需要个体营业执照吗/100个经典创意营销方案

1.默认浏览器打开网站 import process&#xff1b; process.execute("网址")打开网址 wb.go("网址") 2. WEB窗体最大化、最小化 //点击最大化,但是这个函数如果发现最大化会还原窗口,并返回一个值表示当前是否最大化winform.hitmax()//点击最小化按钮wi…...

遵义市住房城乡建设局网站/天津优化加盟

目录实验准备实验总结参考实验准备 准备两台笔记本电脑&#xff0c;两个USB转TTL&#xff08;一个的 RX接另一个的TX&#xff0c;其它的可以不用接&#xff09;。 实验 打开串口调试助手&#xff0c;选择好端口&#xff0c;打开图片文件并发送&#xff1a; 在另一台电脑上即…...

网页qq邮箱怎么发文件给别的邮箱/seo网站培训优化怎么做

&#xff08;1&#xff09;Javascript的变量命名需要注意的3点&#xff1a;1&#xff09;&#xff0c;变量以字母开头&#xff0c;中间可以出现数字或者下划线“_”字符。变量名不能有空格&#xff0c;“”&#xff0c;“-”&#xff0c;“&#xff0c;”等特殊字符。2&#xf…...

wordpress会员发布文章/上海公司排名

设置定时任务很简单&#xff0c;用Timer类就搞定了。一、延时执行首先&#xff0c;我们定义一个类&#xff0c;给它取个名字叫TimeTask&#xff0c;我们的定时任务&#xff0c;就在这个类的main函数里执行。代码如下&#xff1a;package test;import java.util.Timer;public cl…...