IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 手写JavaScript中的call()、apply()和bind() -> 正文阅读

[JavaScript知识库]手写JavaScript中的call()、apply()和bind()

call()

定义:

call()为函数中的一个方法, 其参数为一个指定的this值,以及一个参数列表

语法:

fn.call(thisArg, a,b,c)
  • thisArg:在fu函数运行时指定this的值,如果指定为null或者undefined会指向全局对象,浏览器中就是window对象。
  • a,b,c:参数列表,作为参数传给fu函数

也就是说call能使fn函数中的this指向其第一个参数thisArg对象

const obj1 = {
    name: 'ahua',
    getName(h1,h2) {
        console.log(`我叫${this.name},喜欢${h1}${h2}`); 
    }
};

const obj2 = {
    name: '阿花'
};
obj1.getName.call(obj2,'读书','看报')
// 我叫阿花,喜欢读书和看报

手写call()

  1. call支持多个参数,可能一个,可能一个也没有
  2. 多参数时要把thisArg外的参数传给扩展方法
  3. 结束后要把扩展的自定义函数删除
Function.prototype.mycall = function(context){
	// context 就是上面call的参数obj2,因为只有一个形参,所以后面两个参数会被忽略
	// 如果没有指定this,this指向window
    var context = context || window;
    // 调用mycall的是obj1对象的getName函数,所以this指向getName函数
    // 这个表达式的意思就是在obj2中定义一个fn去复制getName函数
    context.fn = this;

    var args = [];
    // Javascrip中的函数都有一个Arguments对象实例arguments(类数组),它引用着函数的实参arguments,arguments[num]和其参数一一对应。
    // 将mycall中第一个参数thisArg对象(obj2)移除,剩余的('读书','看报')作为fn的参数
  for (var i = 1, len = arguments.length; i < len; i++) {
    args.push(arguments[i]);
  }
  const result = context.fn(...args);
  // 删除fn方法
  delete context.fn;
  return result;
  }
  obj1.getName.mycall(obj2,'读书','看报')
 // 我叫阿花,喜欢读书和看报

apply()

定义:

apply() 为函数的一个方法, 其参数为一个指定的this值,以及一个数组(或类似数组的对象)

语法:

fu.apply(thisArg, [argsArray])
  • thisArg:在fu函数运行时指定this的值,如果指定为null或者undefined会指向全局对象,浏览器中就是window对象。
  • arrgsArray:一个数组或者类数组对象,作为参数传给fu函数

apply也能使函数中的this指向其第一个参数thisArg对象

const obj1 = {
    name: 'ahua',
    getName(x,y) {
        console.log(`我叫${this.name},喜欢${x}${y}`); 
    }
};

const obj2 = {
    name: '阿花'
};
obj1.getName.apply(obj2,['吃饭','睡觉']) 

// 我叫阿花,喜欢吃饭和睡觉

手写apply

apply不同的就是第二个参数变成了数组

Function.prototype.myapply = function(content) {
     // 如果没有传或传的值为空对象 context指向window
     if (typeof context === "undefined" || context === null) {
         context = window
     }
     let args = [...arguments].slice(1) //效果同mycall中的for循环
     // 给obj2添加一个方法fn(复制this) 因为是getName调用的myapply所以this指向getName
     content.fn = this 
     // arguments引用着myapply的两个参数,第一个是obj2,第二个是['吃饭','睡觉']
     const result = content.fn(arguments[1][0],arguments[1][1])//执行fn
     delete content.fn //删除方法
	 return result
 }  obj1.getName.myapply(obj2,['吃饭','睡觉'])
 // 我叫阿花,喜欢吃饭和睡觉

bind()

用法和call类似,不过bind()会创建一个新的函数,需要再次进行调用

function a(x, y, z){
	return this.name + '喜欢' + x + '、' + y + '和' + z;
}
 
var b = {name : '阿花'};
a.getName.bind(b,'读书','看报')('滑板')
// 阿花喜欢读书、看报和滑板	

手写bind()

  1. 函数调用
  2. 改变this
  3. 返回一个绑定this的函数
  4. 接收多个参数
  5. 支持柯里化形式传参 fn(1)(2)(3)

代码实现

Function.prototype.mybind = function(context){
     if (typeof context === "undefined" || context === null) {
         context = window
     }
     // a.mybind(b,参数1,参数2)(参数3)  context是b args是通过arguments获取参数1和参数2  return函数中的参数是参数3
	var args = [...arguments].slice(1);
    // args['读书','看报']
   
    // 保存this,因为如果后面进入return函数后,this的指向会改变
	var self = this;

    // 调用bind后返回一个this指向第一个参数(b)的函数
	return function(){
        // 将类数组转换为数组  innerArgs ['滑板']
		var innerArgs = [...arguments];

        // 实现函数curry:把接受多个参数的函数变换成接受一个单一参数的函数
        // 即:将bind(thisArg,参数1,参数2)(参数3) 中的参数1,参数2,参数3合并为一个参数作为apply的第二个参数
		var finalArgs = args.concat(innerArgs);
		//finalArgs ['读书','看报' ,'滑板']

        // 用apply是因为传入的第二个参数为数组
		return self.apply(context, finalArgs);
	}
}
// 测试结果
function a(x, y, z){
	return this.name + '喜欢' + x + '、' + y + '和' + z;
}
 
var b = {name : '阿花'};
 
a.mybind(b, '读书', '看报')('滑板');
// 阿花喜欢读书、看报和滑板	
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-21 20:40:43  更:2022-03-21 20:44:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:07:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码