美文网首页
js中call、apply、bind

js中call、apply、bind

作者: Mica_马超 | 来源:发表于2019-05-20 10:34 被阅读0次

call apply bind都有着改变this指向的功能,什么叫改变this指向呢?this:当前作用域的顶层对象。某个方法内可能引用了他当前作用域的对象的属性,改变this指向就是把他的this更换为其他对象。这么做的意义是什么呢?话不多说,上代码。

    const Animal = {
        name: '动物',
        say() {
            console.log(`大家好,我是${this.name}`)
        }
    }


    const Cat = {
        name: '大狸猫'
    }


    Animal.say.call(Cat)
    // 大家好,我是大狸猫

    Animal.say.apply(Cat)
    // 大家好,我是大狸猫
    
    Animal.say.bind(Cat)()
    // 大家好,我是大狸猫

上图三个方法都能通过传参改变Animal.say方法中的thiscall apply bind都是Function.prototype上的方法,通过传参的方式把内部this替换为参数中的对象。来看区别,为什么bind后面还跟了个括号?括号表示调用,逆向思考可以得知,bind方法返回了一个新的函数,手动执行才能调用。callapply都是直接调用。bind写法虽然看上去麻烦点,但如果你此时不想调用而是在未来的某一刻调用,这个时候就可以赋值给一个变量,等到需要的时候再调用了

    const Animal = {
        name: '动物',
        say(food, sport) {
            console.log(`大家好,我是${this.name}, 我喜欢吃${food},我喜欢的运动是${sport}`)
        }
    }


    const Cat = {
        name: '大狸猫'
    }


    Animal.say.call(Cat, '猫草', '抓老鼠')
    // 大家好,我是大狸猫, 我喜欢吃猫草,我喜欢的运动是抓老鼠

    Animal.say.apply(Cat, ['猫草', '抓老鼠'])
    // 大家好,我是大狸猫, 我喜欢吃猫草,我喜欢的运动是抓老鼠

    Animal.say.bind(Cat)('猫草', '抓老鼠')
    // 大家好,我是大狸猫, 我喜欢吃猫草,我喜欢的运动是抓老鼠

可以看出,额外参数都紧跟在第一个参数之后,callbind参数以散列形式,apply参数以数组形式,并推理出apply拥有打散数组的功能

    const Animal = {
        name: '动物',
        say(food, sport) {
            console.log(`大家好,我是${this.name}, 我喜欢吃${food},我喜欢的运动是${sport}`)
        }
    }

    const Cat = {
        name: '大狸猫'
    }

    Animal.say.bind(Cat)('猫草', '抓老鼠')
    // 大家好,我是大狸猫, 我喜欢吃猫草,我喜欢的运动是抓老鼠
    
    Animal.say.bind(Cat, '猫草1')('猫草', '抓老鼠')
    // 大家好,我是大狸猫, 我喜欢吃猫草1,我喜欢的运动是猫草

    Animal.say.bind(Cat, '猫草1', '抓老鼠1')('猫草', '抓老鼠')
    // 大家好,我是大狸猫, 我喜欢吃猫草1,我喜欢的运动是抓老鼠1

以上代码可以看出,bind方法产数传递,如果bind方法内有参数以bind方法内参数为主。

实际应用
    import React from 'react'

    export default class App extends React.component {
        state = {
            age: 24
        }
        
        constructor() {
            super()
            this.checkAdult = this.checkAdult.bind(this)
        }

        checkAdult() {
            console.log(this.state.age >= 18 ? '成年了' : '未成年')
        }

        render() {
            return (
                <button onClick={this.checkAdult}>检测</button>
            )
        }
    }

react中,我们在可以在构造函数内实现this绑定(当然我们也可以使用箭头函数或者public class fields语法(stage 2)直接在class内赋值)
react相关this指向相关问题

Math.max.apply(Math, [5, 2, 6, 9, 20, 12])

数组的求最大值(也可以使用es6的扩展运算符Math.max(...arr))

继承

    function Animal(sound) {
        this.sound = sound
        this.say = function() {
            console.log(this.sound)
        }
    }

    function Dog() {
        Animal.apply(this, arguments)
    }

    const dog = new Dog('wang wang')

    dog.say()
    // wang wang

在构造函数Dog内使用call或者apply,此时Animal的所有属性和方法都被在此声明,实现继承

伪数组转换成数组

伪数组也称类数组。像arguments 或者 获取一组元素返回的集合都是伪数组。
(arguments,NodeList)

    const imgArr = Array.prototype.slice.call(document.querySelectorAll('img'))

    function Dog() {
        const ages = Array.prototype.slice.call(arguments)
    }

当然也可以用ES6简单写法

const arg = Array.from(arguments);
const arg = [...arguments]
console.log(arg instanceof Array)
// true

Array.from() 能将类数组(arguments,NodeList),可迭代对象 (Set,Map),字符串(String)转换成数组
Array.prototype.slice.call() 能将类数组(arguments,NodeList),字符串(String)转换成数组

总结

  • call apply bind都有着改变this指向的作用,并且第一个参数都是目标this对象,bind返回一个新的函数
  • 额外参数下,callbind的参数都以散列形式,apply以数组形式

在不破坏原对象的情况下,使用这几个方法是最好的选择。但随着新版es的出现,他们的大部分功能都已能被新的语法糖替代。不过对于开发者来说,但还是应该要了解的,这些知识经常出现在面试题中,况且只有了解原理才能更熟练的掌握新语法的用法,小到api,大到框架,脚踏实地,才能走得更高。

相关文章

网友评论

      本文标题:js中call、apply、bind

      本文链接:https://www.haomeiwen.com/subject/indhzqtx.html