JavaScript学习笔记(十) call、apply、bind

简介: JavaScript学习笔记(十) call、apply、bind

前言


call、apply、bind 都是定义在函数原型上的,也就是说每个函数都能调用这些方法

那么它们都有什么作用呢?它们之间存在什么异同呢?下面让我们一起来探讨一下


正文


1、call


call 可以用于改变函数的执行环境,简单来说就是可以改变函数内部 this 的指向


使用 call 可以让一个对象借用另外一个对象的方法,可以借此实现继承


第一个传入的参数是上下文执行环境,即函数运行时 this 的指向,之后传入的参数将会直接传递给调用函数


在 call 调用完成后,返回调用函数的返回值


// 借用方法
let apple = {
    color: 'red',
    getColor: function() { return this.color }
}
let banana = {
    color: 'yellow'
}
let color = apple.getColor.call(banana)
console.log(color)
/*
 * 执行结果:
 * yellow
**/
// 实现继承
function Parent(age, name) {
    this.age = age
    this.name = name
    this.getName = function() { return this.name }
    this.setName = function(name) { this.name = name }
}
function Child(age, name) {
    Parent.call(this, age, name)
}
let child = new Child(18, 'Peter')
child.setName('Steve')
let name = child.getName()
console.log(name)
/*
 * 执行结果:
 * Steve
**/


2、apply


apply 的作用与 call 完全一样,都能用于改变函数的执行环境,两者的区别仅仅在于传入的参数


第一个参数传入的都是上下文执行环境,即函数运行时 this 的指向,参数的区别在于之后传入的参数


之后传入的参数是调用函数执行所需的参数,call 是按照顺序直接传入,apply 是将参数放在数组中再传入


// 判断类型
let number = 0
let string = ''
let boolean = true
let object = {}
let array = []
function typeOf(value) {
    return Object.prototype.toString.apply(value).slice(8, -1)
}
console.log(typeOf(number))
console.log(typeOf(string))
console.log(typeOf(boolean))
console.log(typeOf(object))
console.log(typeOf(array))
/*
 * 执行结果:
 * Number
 * String
 * Boolean
 * Object
 * Array
**/
// 数值求和
function addNumber() {
    let isNumber = function(value) { return typeof value === 'number' }
    let numbers = Array.prototype.filter.apply(arguments, [isNumber])
    let sum = numbers.reduce(function(prev, curr) {
        return prev + curr
    })
    return sum
}
let result = addNumber(1, 'a', 2, 'b', 3, 'c')
console.log(result)
/*
 * 执行结果:
 * 6
**/


3、bind

传入 bind 的参数与 call 完全相同,作用也与 call 大致一样,但它们还是有所区别的

call 在调用后马上执行函数,bind 不会,调用 bind 返回一个改变了上下文的新函数,可以在需要的时候再调用

// 借用方法
let apple = {
    color: 'red',
    getColor: function() { return this.color }
}
let banana = {
    color: 'yellow'
}
let getColorForBanana = apple.getColor.bind(banana)
console.log(getColorForBanana)
let color = getColorForBanana()
console.log(color)
/*
 * 执行结果:
 * ƒ () { return this.color }
 * yellow
**/


// 解决回调函数 this 指向的问题
let object = {
    value: 0,
    asyncPrint: function() {
        setTimeout(function() { console.log(this.value) }, 2000)
    },
    asyncPrintWithThat: function() {
        let that = this
        setTimeout(function() { console.log(that.value) }, 2000)
    },
    asyncPrintWithBind: function() {
        setTimeout(function() { console.log(this.value) }.bind(this), 2000)
    }
}
object.asyncPrint()
object.asyncPrintWithThat()
object.asyncPrintWithBind()
/*
 * 执行结果:
 * undefined
 * 0
 * 0
**/


4、手动实现三个函数


  • call
Function.prototype.myCall = function(cxt, ...params) {
    // 处理传入的上下文执行环境
    // 若为 null 或 undefined,则要转换成全局对象
    // 若为 原始值,也要转换成对应的实例对象
    const context = (cxt !== null && cxt !== undefined) ? Object(cxt) : window
    // 创建一个临时属性
    // 为了避免属性冲突,这里使用 Symbol 数据类型
    const property = Symbol('property')
    // 设置临时属性的值为调用函数
    context[property] = this
    // 通过对象方法调用函数,此时 this 指向 context,也就是指向了传入的上下文对象
    let result = context[property](...params)
    // 调用完成之后,删除方法,避免污染传入对象
    delete context[property]
    // 返回执行结果
    return result
}


  • apply
Function.prototype.myApply = function(cxt, arr) {
    // 处理传入的上下文执行环境
    const context = (cxt !== null && cxt !== undefined) ? Object(cxt) : window
    // 创建一个临时属性
    const property = Symbol('property')
    // 设置临时属性的值为调用函数
    context[property] = this
    // 声明执行结果
    let result = null
    // 用于检测传入的参数是否为类数组
    function isArrayLike(value) {
        if (value &&
            typeof value === 'object' &&
            isFinite(value.length) &&
            value.length >= 0 &&
            value.length === Math.floor(value.length) &&
            value.length < 4294967296) {
            return true
        } else {
            return false
        }
    }
    // 是否传入第二个参数
    if (arr) {
        // 第二个参数是否为类数组
        if (isArrayLike(arr)) {
            let params = Array.from(arr)
            result = context[property](...params)
        } else {
            throw new TypeError()
        }
    } else {
        result = context[property]()
    }
    // 调用完成之后,删除方法,避免污染传入对象
    delete context[property]
    // 返回执行结果
    return result
}


  • bind
Function.prototype.myBind = function(cxt, ...outerParams) {
    let self = this
    let bound = function(...innerParams) {
        // 判断绑定好的函数是否通过 new 调用
        // 如果通过 new 调用,则绑定到 this;否则就绑定到传入的上下文执行环境
        const context = (this instanceof bound) ? this : cxt
        // 通过 call 模拟实现
        return self.call(context, ...outerParams, ...innerParams)
    }
    // 使得绑定好的函数与调用 bind 的函数处于同一原型链上
    bound.prototype = Object.create(this.prototype)
    // 返回绑定好的函数
    return bound
}


目录
相关文章
|
4天前
|
JavaScript 前端开发
js中的bind,call,apply方法的区别以及用法
JavaScript中,`bind`、`call`和`apply`均可改变函数的`this`指向并传递参数。其中,`bind`返回一个新函数,不立即执行;`call`和`apply`则立即执行,且`apply`的参数以数组形式传递。三者在改变`this`指向及传参上功能相似,但在执行时机和参数传递方式上有所区别。
|
30天前
|
JavaScript 前端开发
JS高级—call(),apply(),bind()
【10月更文挑战第17天】call()`、`apply()`和`bind()`是 JavaScript 中非常重要的工具,它们为我们提供了灵活控制函数执行和`this`指向的能力。通过合理运用这些方法,可以实现更复杂的编程逻辑和功能,提升代码的质量和可维护性。你在实际开发中可以根据具体需求,选择合适的方法来满足业务需求,并不断探索它们的更多应用场景。
10 1
|
1月前
|
JavaScript 前端开发
js 中call()和apply()
js 中call()和apply()
28 1
|
2月前
|
JavaScript 前端开发 API
Vue学习笔记3:对比纯JavaScript和Vue实现数据更新的实时视图显示
Vue学习笔记3:对比纯JavaScript和Vue实现数据更新的实时视图显示
|
2月前
|
自然语言处理 JavaScript 前端开发
JS中this的应用场景,再了解下apply、call和bind!
该文章深入探讨了JavaScript中`this`关键字的多种应用场景,并详细解释了`apply`、`call`和`bind`这三个函数方法的使用技巧和差异。
|
1月前
|
JavaScript 前端开发
【干货分享】JavaScript学习笔记分享
【干货分享】JavaScript学习笔记分享
57 0
|
定位技术
arcgisapi for javascript4.0学习笔记4.0新特性
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gisdoer/article/details/51842547 arcgisapi for javascript4.
784 0
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的客户关系管理系统附带文章源码部署视频讲解等
97 2
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的小区物流配送系统附带文章源码部署视频讲解等
128 4
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的宠物援助平台附带文章源码部署视频讲解等
82 4