js中call、apply和bind:

news2024/10/6 12:29:21

文章目录

        • 一、区别:
        • 二、案例:
        • 三、实现:
            • 【1】call实现
            • 【2】apply实现
            • 【3】bind实现


一、区别:

call、apply、bind相同点:都是改变this的指向,传入的第一个参数都是绑定this的指向,在非严格模式中,如果第一个参数是nul或者undefined,会把全局对象(浏览器是window)作为this的值,要注意的是,在严格模式中,null 就是 null,undefined 就是 undefined

call和apply唯一的区别是:call传入的是参数列表,apply传入的是数组,也可以是类数组

bind和call、apply的区别: bind返回的是一个改变了this指向的函数,便于稍后调用,不像call和apply会立即调用;bind和call很像,传入的也是参数列表,但是可以多次传入,不需要像call,一次传入
值得注意:当 bind 返回的函数 使用new作为构造函数时,绑定的 this 值会失效,this指向实例对象,但传入的参数依然生效 (new调用的优先级 > bind调用)

在这里插入图片描述

二、案例:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、实现:

【1】call实现

对象context想调用一个它没有的方法f 怎么办呢?f.call(context) 通过call来借用方法f ,怎么做到的呢

  1. 对象context添加f方法
  2. 对象context执行f方法
Function.prototype.myCall = function(context, ...arg) {
    // 如果第一个参数传入的是undefined和null,context为window对象
    context = context || window;  
     
    // 为context对象添加函数bar
    context.fn = this;   // this:bar,this指向调用myCall的bar  
 
    // context对象执行函数bar,并返回结果
    return  context.fn(...arg); 
}
 
// 测试一下
var value = 2;
 
var obj = {
    value: 1
}
function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}

bar.myCall(null); // 2  this指向window
 
console.log(bar.myCall(obj, 'kevin', 18)); //1  this指向obj  Object { value: 1,name: 'kevin',age: 18}
【2】apply实现

apply和call唯一的区别是:call传入的是参数列表,apply传入的是数组,也可以是类数组

Function.prototype.myApply = function(context, arg) {
    // 如果第一个参数传入的是undefined和null,context为window对象
    context = context || window;  
     
    // context对象添加函数bar
    context.fn = this;   // this:bar,this指向调用myCall的函数bar  
 
    // context对象执行函数bar,并返回结果
    let result = null;
    if (!arg) { // 没有传入数组
        result = context.fn();
    }else{      // 传入了参数数组
        result = context.fn(...arg);
    } 
    return result;
}
 
// 测试一下
var value = 2;
 
var obj = {
    value: 1
}
function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}
 
bar.myApply(null); // 2 
console.log(bar.myApply(obj, ['kevin', 18])); // 1   传入的是数组['kevin', 18]
【3】bind实现

bind和call、apply的区别: bind返回的是一个改变了this指向的函数,便于稍后调用,不像call和apply会立即调用;bind和call很像,传入的也是参数列表,但是可以多次传入,不需要像call,一次传入
值得注意:当 bind 返回的函数 使用new作为构造函数时,绑定的 this 值会失效,this指向实例对象,但传入的参数依然生效 (new调用的优先级 > bind调用)
bind实现最为复杂,因为经过bind绑定过的函数,既可以被当作普通函数调用,又可以被当作构造函数调用

Function.prototype.myBind = function (context, ...args){
    // 如果第一个参数传入的是undefined和null,context为window对象
    context = context || window;
 
    // context对象添加函数Person
    context.fn = this;     // this:Person,context.fn:Person,_this:Person
    let _this = this;
     
    // bind返回的函数 
    const result = function (...innerArgs) { 
        if (this instanceof _this ) { // this:a (new出来的实例对象) ,  _this:Person
            // 为实例对象a添加Person方法
            this.fn = _this;
            // 实例对象a执行Person方法
            this.fn(...[...args,...innerArgs]);
        }else{
            // 普通函数被调用
            context.fn(...[...args,...innerArgs]);
        }
    }
     
    result.prototype = Object.create(this.prototype);  // 为什加这一句?看原型图下面会解释
    return result;
}
 
// 测试
// function Person(name, age) {
//   console.log(name); //'我是第一次参数传进来的name被args接收'
//   console.log(age); //'我是第二次参数传进来的age被innerArgs接收'
//   console.log(this); //构造函数this指向实例对象
// }
// // 构造函数原型的方法
// Person.prototype.say = function() {
//   console.log(123);
// }
 
// let obj = {
//   objName: '我是obj传进来的name',
//   objAge: '我是obj传进来的age'
// }
 
// // bind 返回的函数 作为构造函数调用
// let bindFun = Person.myBind(obj, '我是第一次参数传进来的name被args接收') // this:obj
// let a = new bindFun('我是第二次参数传进来的age被innerArgs接收')               // this:a
// a.say() //123
 
// 测试
let obj = {
  objName: '我是obj传进来的name',
  objAge: '我是obj传进来的age'
}
 
// 普通函数
function normalFun(name, age) {
  console.log(name);          //'我是第一次参数传进来的name'
  console.log(age);           //'我是第二次参数传进来的age'
  console.log(this === obj);  // true
  console.log(this.objName);  //'我是obj传进来的name'
  console.log(this.objAge);   //'我是obj传进来的age'
}
 
// bind 返回的函数 作为普通函数调用
let bindFun = normalFun.myBind(obj, '我是第一次参数传进来的name被args接收'); // this指向obj 
bindFun('我是第二次参数传进来的age被innerArgs接收');

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/974250.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入协议栈了解TCP的三次握手、四次挥手、CLOSE-WAIT、TIME-WAIT。

TCP网络编程的代码网上很多,这里就不再赘述,简单用一个图展示一下tcp网络编程的流程: 1、深入connect、listen、accept系统调用,进一步理解TCP的三次握手 这三个函数都是系统调用,我们可以分为请求连接方和被…

文案生成器-文章生成器

你是否曾经面对过频繁写作文案的问题?是不是觉得文案的撰写过程既繁琐又耗时?那么今天我要向你介绍一项令人兴奋的技术——文案自动生成。是的,现在我们可以借助人工智能技术,自动生成高质量的文案,为你在营销和推广方…

C++笔记基础全部完整版

01 面向对象 基本概念 面向对象程序设计(Object-Oriented Programming,OOP)是一种新的程序设计范型。程序设计范型是指设计程序的规范、模型和风格,它是一类程序设计语言的基础。 面向过程 面向过程程序设计范型是使用较广泛的…

【AIGC专题】Stable Diffusion 从入门到企业级实战0401

一、概述 本章是《Stable Diffusion 从入门到企业级实战》系列的第四部分能力进阶篇《Stable Diffusion ControlNet v1.1 图像精准控制》第01节, 利用Stable Diffusion ControlNet Inpaint模型精准控制图像生成。本部分内容,位于整个Stable Diffusion生…

遥感指数数据库

目前遥感指数多种多样,那怎么针对不同的应用领域选择合适的植被指数?不同卫星又有哪些可以反演的指数? Henrich等人开发了Index Database(网址:https://www.indexdatabase.de/),总结了目前主流的遥感指数,…

EMERSON 1X00781H01L电源模块

应用领域: EMERSON 1X00781H01L 电源模块广泛用于工业自动化、电力系统、通信设备、机器人技术和其他领域,以确保设备和系统的正常运行。 电源输出: 该电源模块通常提供不同的电压和电流输出选项,以满足不同设备和系统的电源需求…

Python(Web时代)—— Django管理工具

介绍 前言 通过模型我们可以进行数据库的操作,如果我们想要对数据表中的数据进行操作还需要单独的开发接口,颇有不方便,今天我们来通过Django提供的管理工具来编辑模型数据。 Django 为我们提供了强大的工具,可以全自动地根据模…

go语言--堆栈

根据隔离适应策略,使用内存时的最小单位为mspan 每个mspan为N个相同大小的“格子 Go中一共有67种mspan

算法:图解递归算法的应用场景和使用途径

文章目录 什么是递归?使用递归的原因?如何理解递归?递归的使用写法典型例题和分析汉诺塔问题合并两个有序链表反转链表两两交换链表中的节点pow 总结 什么是递归? 递归就是函数自己调用自己的情况,在二叉树&#xff0…

Spring Bean 别名处理原理分析

今天来和小伙伴们聊一聊 Spring 中关于 Bean 别名的处理逻辑。 1. Alias 别名,顾名思义就是给一个 Bean 去两个甚至多个名字。整体上来说,在 Spring 中,有两种不同的别名定义方式: 定义 Bean 的 name 属性,name 属性…

[machine learning]神经网路初步 basic neural network

这一篇写的很差....我会找时间慢慢补充的 1.神经网络是什么 在上一篇关于逻辑回归的博客中,简单介绍了逻辑回归模型,对于监督学习来说,模型可以理解为一个模块/函数,在足够的数据训练以后,通过梯度下降等手段进行拟合,最终根据输入来预测输出结果. 这一个东西,我们可以称之为…

修改了字符集,好多软件不能正常使用,所以,慎重。。。。

这里,默认是没有选中的。所以,你千万不要随便就选中了。(terminal里乱码的问题,可以通过命令: chcp 65001 解决)。如果你执意选中了这里,重启之后,至少4个软件异常: 1、…

华为OD机试 - TLV解析Ⅰ(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、Java算法源码五、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(A卷B卷)》。 …

集成图片验证码Kaptcha-完成登录验证功能

下面展示的是用SpringBoot集成Kaptcha&#xff0c;当然用其他框架也是一样的。 导入Kaptcha 导入pom.xml&#xff0c;下面得到二选一&#xff0c;建议用github的&#xff0c;比google的快一点 <dependency><groupId>com.github.penggle</groupId><arti…

2024腾讯校招后端面试真题汇总及其解答(三)

21【算法题】反转链表 题目: 给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。 示例 1: 输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2: 输入:head = [1,2] 输出:[2,1]示例 3: 输入:head = [] 输出:[]提示: 链表中节点的数目范围是 [0, 5…

Chrome 和 Edge 上出现“status_breakpoint”错误解决办法

文章目录 STATUS_BREAKPOINTSTATUS_BREAKPOINT报错解决办法Chrome浏览器 Status_breakpoint 错误修复- 将 Chrome 浏览器更新到最新版本- 卸载不再使用的扩展程序和应用程序- 安装计算机上可用的任何更新&#xff0c;尤其是 Windows 10- 重启你的电脑。 Edge浏览器 Status_brea…

基于 Flink CDC 构建 MySQL 和 Postgres 的 Streaming ETL

官方网址&#xff1a;https://ververica.github.io/flink-cdc-connectors/release-2.3/content/%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B/mysql-postgres-tutorial-zh.html官方教程有些坑&#xff0c;经过自己实测&#xff0c;记录个笔记。 服务器环境&#xff1a; VM虚拟机&am…

HarmonyOS 实现表单页面的输入,必填校验和提交

一. 样例介绍 本篇 Codelab 基于 input 组件、label 组件和 dialog 组件&#xff0c;实现表单页面的输入、必填校验和提交&#xff1a; 1. 为 input 组件设置不同类型&#xff08;如&#xff1a;text&#xff0c;email&#xff0c;date 等&#xff09;&#xff0c;完成表单页…

Burp插件HaE与Authz用法

HaE与Authz均为BurpSuite插件生态的一员&#xff0c;两者搭配可以避免“越权”、“未授权”两类漏洞的重复测试行为。&#xff08;适用于业务繁杂&#xff0c;系统模块功能多的场景&#xff09; 两个插件都可以在store里安装 安装完后&#xff0c;点击Filter Settings勾选Sho…