JS中bind、call和apply的作用以及在TS装饰器中的用法
1,前言
bind
、call
和apply
在函数式编程时候非常有用,本文旨在记录一下我遇到过的一些用法和知识点,也记录一下在装饰器中的用法。
1,call
call()
方法使用一个指定的this
值和单独给出的一个或多个参数来调用一个函数。它的第一个参数是你需要指向的this
目标,后面的参数是你需要传递的参数,无参数可以不写。
语法:
function.call(target, arg1, arg2, ...)
1.1,例子
如下,控制台会打印出:快看【张三】在奔跑
const Person = {
Name: '张三',
Run() {
return `快看【${this.Name}】在奔跑`
}
}
const Animal = {
Name: '猛犸象'
}
console.log(Person.Run()) // 打印出:快看【张三】在奔跑
让我们使用call
改变下this
指向
1.2,直接调用
如果没有传递第一个参数,this
的值将会被绑定为全局对象,也就是window
对象(浏览器环境)。由于在window
上找不到this.Name
这个属性,控制台会打印出:快看【undefined】在奔跑
console.log(Person.Run.call()) // 打印出:快看【undefined】在奔跑
1.3,将this指向另一个对象
此时this
会绑定为被指向的对象,控制台会打印出:快看【猛犸象】在奔跑
console.log(Person.Run.call(Animal)) // 打印出:快看【猛犸象】在奔跑
1.4,传递参数
const Person = {
Name: '张三',
Run(param1, param2) {
console.log(param1)
console.log(param2)
return `快看【${this.Name}】在奔跑`
}
}
const Animal = {
Name: '猛犸象'
}
console.log(Person.Run.call(Animal, 10, '100')) // 打印出:10、'100'、快看【猛犸象】在奔跑
2,apply
apply()
方法调用一个具有给定this
值的函数,以及以一个数组(或类数组对象)的形式提供的参数。它的第一个参数是你需要指向的this
目标,后面的参数是你需要传递的数组参数,无参数可以不写。
语法:
function.apply(target, [argsArray])
2.1,例子
如下,控制台会打印出:快看【张三】在奔跑
const Person = {
Name: '张三',
Run() {
return `快看【${this.Name}】在奔跑`
}
}
const Animal = {
Name: '猛犸象'
}
console.log(Person.Run()) // 打印出:快看【张三】在奔跑
让我们使用apply
改变下this
指向
2.2,直接调用
如果没有传递第一个参数,this
的值将会被绑定为全局对象,也就是window
对象(浏览器环境)。由于在window
上找不到this.Name
这个属性,控制台会打印出:快看【undefined】在奔跑
console.log(Person.Run.apply()) // 打印出:快看【undefined】在奔跑
2.3,将this指向另一个对象
此时this
会绑定为被指向的对象,控制台会打印出:快看【猛犸象】在奔跑
console.log(Person.Run.apply(Animal)) // 打印出:快看【猛犸象】在奔跑
2.4,传递参数
const Person = {
Name: '张三',
Run(...arg) {
console.log(arg)
return `快看【${this.Name}】在奔跑`
}
}
const Animal = {
Name: '猛犸象'
}
console.log(Person.Run.apply(Animal, [10, '100'])) // 打印出:[10、'100']、快看【猛犸象】在奔跑
2.5,合并数组
let arr = ['a', 'b']
let elements = [0, 1, 2]
array.push.apply(arr, elements)
console.log(arr) // ["a", "b", 0, 1, 2]
3,bind
bind()
方法创建一个新的函数,在bind()
被调用时,这个新函数的this
被指定为bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
语法:
function.bind(target, arg1, arg2, ...)
3.1,例子
如下,控制台会打印出:快看【张三】在奔跑
const Person = {
Name: '张三',
Run() {
return `快看【${this.Name}】在奔跑`
}
}
const Animal = {
Name: '猛犸象'
}
console.log(Person.Run()) // 打印出:快看【张三】在奔跑
让我们使用apply
改变下this
指向
3.2,直接调用
如果没有传递第一个参数,this
的值将会被绑定为全局对象,也就是window
对象(浏览器环境)。由于在window
上找不到this.Name
这个属性,控制台会打印出:快看【undefined】在奔跑
注意:bind
返回的是一个方法,需要加上()
执行才行
console.log(Person.Run.bind()()) // 打印出:快看【undefined】在奔跑
3.3,将this指向另一个对象
此时this
会绑定为被指向的对象,控制台会打印出:快看【猛犸象】在奔跑
console.log(Person.Run.bind(Animal)()) // 打印出:快看【猛犸象】在奔跑
3.4,传递参数
const Person = {
Name: '张三',
Run(param1, param2) {
console.log(param1)
console.log(param2)
return `快看【${this.Name}】在奔跑`
}
}
const Animal = {
Name: '猛犸象'
}
console.log(Person.Run.bind(Animal, 996, '100')()) // 打印出:996 '100' 快看【猛犸象】在奔跑
4,TypeScript中装饰器使用
使用bind
或者apply
或者call
,可以将方法装饰器中的this
指向被装饰的方法,不影响原方法使用的同时,注入新的逻辑处理。
function GetHttp(param: string) {
return function (target: any, Name: any, desc: any): void {
console.log(target) // 原型
console.log(Name) // 方法名
console.log(desc) // 方法描述 desc.value即是该方法
const ev = desc.value
desc.value = function(): void {
console.log('我是改写后的function')
ev.call(this)
}
}
}
class HttpGet {
name: string
constructor(name: string) {
this.name = name
}
@GetHttp('方法装饰器')
request(): void {
console.log(this.name)
}
}
const HttpObj = new HttpGet('小红')
HttpObj.request()
// 打印出:方法装饰器、我是改写后的function、小红
5,总结
5.1,相同点
- 都可以通过指定第一个参数,改变
this
指向 - 都可以传递参数
5.2,不同点
bind
返回的是一个函数,需要加上()
来执行apply
传递参数需要数组的形式
如果看了觉得有帮助的,我是@鹏多多,欢迎 点赞 关注 评论;END
PS:在本页按F12,在console中输入document.querySelectorAll('.diggit')[0].click(),有惊喜哦
公众号
往期文章
- 助你上手Vue3全家桶之Vue-Router4教程
- 助你上手Vue3全家桶之Vue3教程
- 助你上手Vue3全家桶之VueX4教程
- 使用nvm管理node.js版本以及更换npm淘宝镜像源
- 超详细!Vue-Router手把手教程
- vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
- 微信小程序实现搜索关键词高亮
- 超详细!Vue的九种通信方式
- 超详细!Vuex手把手教程
个人主页
JS中bind、call和apply的作用以及在TS装饰器中的用法的更多相关文章
- python_如何修改装饰器中参数?
案例: 为分析程序内哪些函数执行时间开销较大,我们需定义一个带timeout参数的装饰器 需求: 统计被装饰函数的运行时间 时间大于timeout时,将此次函数调用记录到log日志中 运行时可以修改t ...
- 快速理解js中的call,apply的作用
今天被人问到js中的call,apply的区别和用途,解释了一番后,想到之前在逼乎上看到一位小伙伴生动形象的解释 本身不难理解,看下MDN就知道了,但是不常用,遇到了,还要脑回路回转下.或者时间长了, ...
- python装饰器中@wraps作用--修复被装饰后的函数名等属性的改变
Python装饰器(decorator)在实现的时候,被装饰后的函数其实已经是另外一个函数了(函数名等函数属性会发生改变),为了不影响,Python的functools包中提供了一个叫wraps的de ...
- 【转】odoo 新API装饰器中one、model、multi的区别
http://blog.csdn.net/qq_18863573/article/details/51114893 1.one装饰器详解 odoo新API中定义方式: date=fields.Date ...
- 装饰器中functools的用处
定义一个最简单的装饰器 def user_login_data(f): def wrapper(*args, **kwargs): return f(*args, **kwargs) return w ...
- 装饰器中的@functools.wraps的作用
def login_required(view_func): @functools.wraps(view_func) def wrapper(*args, **kwargs): ...... retu ...
- python装饰器中functools.wraps的作用详解
直接上代码看效果: # 定义一个最简单的装饰器 def user_login_data(f): def wrapper(*args, **kwargs): return f(*args, **kwar ...
- python装饰器中的计时器thd.strat用法
thd = KThread(target=_new_func, args=(), kwargs=new_kwargs) thd.start() thd.join(seconds) alive = th ...
- JSP和Servlet中的几个编码的作用及原理
首先,说说JSP和Servlet中的几个编码的作用. 在JSP和Servlet中主要有以下几个地方可以设置编码,pageEncoding="UTF-8".contentType=& ...
随机推荐
- C++学习 1 数组
一维数组: 定义:1.数据类型 数组名 [ 数组长度 ]: int arr [5];//赋值 arr[0]=10; arr[1]=20; arr[2]=30; arr[3]=40; arr[4]=50 ...
- LeetCode352 将数据流变为多个不相交区间
LeetCode352 将数据流变为多个不相交区间 1 题目 给你一个由非负整数 a1, a2, ..., an 组成的数据流输入,请你将到目前为止看到的数字总结为不相交的区间列表. 实现 Summa ...
- Spring框架访问数据库的两种方式的小案例
1.1 以Xml的方式访问数据库的案例 要以xml的方式访问数据库需要用到JdbcTemplate ,因为 JdbcTemplate(jdbc的模板对象)在Spring 中提供了一个可以操作数据库的对 ...
- C 输入输出函数
流 就C程序而言,所有的I/O操作只是简单地从程序移入或移出字节的事情.这种字节流便称为流( stream ). 绝大多数流是完全缓存的,这意味着"读取"和"写入&quo ...
- 实用 | 利用 aardio 配合 Python 快速开发桌面应用
1. 前言 大家好,我是安果! 我们都知道 Python 可以用来开发桌面应用,一旦功能开发完成,最后打包的可执行文件体积大,并且使用 Python 开发桌面应用周期相对较长 假如想快速开发一款 PC ...
- NX开发 刀路生成
此段是可以生成程序的完整代码,只有从坐标(10,10,10)到(500,500,500)一根刀轨.motion_ptr->feed_value 的值为0时生成G00,非0时生成G01.此代码只有 ...
- Kubernetes client-go 源码分析 - Reflector
概述入口 - Reflector.Run()核心 - Reflector.ListAndWatch()Reflector.watchHandler()NewReflector()小结 概述 源码版本: ...
- C++的智能指针学习笔记(初)
C++ primer plus 16.2节介绍了auto_ptr,该模板类在C++11中已弃用,目前已被shared_ptr代替. auto_ptr又叫做智能指针,用于管理动态内存分配的用法. 为什么 ...
- Spring中属性注入的几种方式以及复杂属性的注入详解
在spring框架中,属性的注入我们有多种方式,我们可以通过set方法注入,可以通过构造方法注入,也可以通过p名称空间注入,方式多种多样,对于复杂的数据类型比如对象.数组.List.Map.Prope ...
- springBoot服务整合线程池ThreadPoolTaskExecutor与@Async详解使用
ThreadPoolExecutor:=======这个是java自己实现的线程池执行类,基本上创建线程池都是通过这个类进行的创建.ThreadPoolTaskExecutor:========这个是 ...