js中call、apply和bind:

文章目录

        • 一、区别:
        • 二、案例:
        • 三、实现:
            • 【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对象添加函数barcontext.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指向windowconsole.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对象添加函数barcontext.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对象添加函数Personcontext.fn = this;     // this:Person,context.fn:Person,_this:Personlet _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);  // trueconsole.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.hqwc.cn/news/99299.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

69、配置AWS服务,接收来自RTSP流的推送

基本思想:在上一篇的基础和视频教程之后,进行简单的aws服务,进行RTSP流的接收 第一步: 第二步:配置video_stream,记得选择香港节点 同时记录这个信息,后面的策略需要填充 第三步:进行策略设置 第四步:策略设置,选中右上角的创建策略 第五步、进行json填充 第六步:填…

Tequila Works x Incredibuild

关于 Tequila Works Tequila Works 是一家位于西班牙马德里的电子游戏开发商,由劳尔鲁比奥 (Raul Rubio) 和卢兹桑乔 (Luz Sancho) 于2009年创立。该公司著名的游戏产品包括《死亡曙光》(Deadlight)、《霜华》(Rime)、《联盟外传:努努之歌》(Song of Nu…

KaiwuDB 受邀亮相 2023 中国国际“软博会”

8月31日,第二十五届中国国际软件博览会(以下简称“软博会”)在天津盛大开幕。KaiwuDB 受邀亮相展会,围绕“塑造软件新生态,赋能发展新变革”主题,重点展示自研分布式多模数据库及各大行业解决方案&#xff…

设计模式之适配器与装饰器

目录 适配器模式 简介 角色 使用 优缺点 使用场景 装饰器模式 简介 优缺点 模式结构 使用 使用场景 适配器模式 简介 允许将不兼容的对象包装成一个适配器类,使得其他类可以通过适配器类与原始对象进行交互,从而提高兼容性 角色 目标角色…

Linux--进程--创建子进程一般目的

父进程创建子进程的目的:简单来说:给特定的输入,给出特定的输出 父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当请求到达,父进程调用fork&…

操作系统强化认识之Shell编程学习与总结

目录 1.Shell的概述 2.Shell脚本入门 3.变量 3.1.系统预定义变量 3.2.自定义变量 3.3.特殊变量 4.运算符 5.条件判断 6.流程控制 6.1.if判断 6.2.case语句 6.3.for循环 6.4.while循环 7.read读取控制台输入 8.函数 8.1.系统函数 8.2.自定义函数 9.正则表示式入…

Upload-labs 1~15 通关详细教程

文章目录 Upload-labs 1~15 通关详细教程Pass-01-前端js验证Pass-02-后端MIME验证Pass-03-黑名单验证Pass-04-黑名单验证.htaccessPass-05-文件后缀名大小写绕过Pass-06-文件后缀名空格绕过Pass-07-文件后缀名点绕过Pass-08-文件后缀名::$DATA绕过Pass-09-点空格点空格绕过Pass…

Unity(三) Shader着色器初探

学习3D开发技术的时候无可避免的要接触到Shader,那么Shader是个什么概念呢?其实对于开发同事来说还是比较难理解的,一般来说Shader是服务于图形渲染的一类技术,开发人员可以通过其shader语言来自定义显卡渲染页面的算法&#xff0…

KMP超高效匹配算法

简介: KMP算法是一种改进的字符串匹配算法,其中,KMP算法的运用核心是利用匹配失败后的信息,最大进度的减少模式串与目标串的匹配次数以达到快速匹配的效果。算法与暴力求解的改进在于每当一趟匹配过程中出现的字符比较不相等时&am…

文件包含漏洞学习小结

目录 一、介绍 二、常见文件包含函数 三、文件包含漏洞代码举例分析 四、文件包含漏洞利用方式 4.1 本地文件包含 1、读取敏感文件 2、文件包含可运行的php代码 ①包含图片码 ②包含日志文件 ③包含环境变量getshell ④临时文件包含 ⑤伪协议 4.2 远程文件包含 4.…

Ubuntu18.04安装docker-io

1. 安装docker 1.1 网上一搜,全是更新仓库、下载依赖、添加docker的gpg密钥、添加docker仓库、安装docker-ce的步骤,但是在安装docker-ce时却提示“package "docker-ce" has no installation candidate”,就很迷。 1.2 安装docke…

CH341 USB总线转接芯片

产品概述: CH341是一个USB总线的转接芯片,通过USB总线提供异步串口、打印口、并口以及常用的2线和4线等同步串行接口。 在异步串口方式下,CH341提供串口发送使能、串口接收就绪等交互式的速率控制信号以及常用的MODEM联络信号,用于…