zoukankan      html  css  js  c++  java
  • 函数2---call、apply、bind

      函数call() apply() bind() 三个方法目的相同: 改变函数中this的指向;三者在使用上存在差异,这导致三者有各种的应用场景:call()、apply()更为接近;

      相同点: call、apply、bind 第一个参数:this指向的对象(上下文),之后的参数为要传入的变量;

      不同点:

    var obj = {name:"Hello , function !"}
    
    function fun(){
        console.log(this.name)  
    }
    
    fun.call(obj)
    fun.apply(obj)
    fun.bind(obj)()
    
    //1.call、apply 使用接近,只是参数传递形式不同
    //2.call、apply 会立即执行函数;bind返回一个绑定obj的函数,不会立即执行(这点很重要!决定了bind的使用场景)

    一,call()

      1.用法:

         call( [obj , [arg1,[arg2,...]]] )

      2.第一个参数obj的取值:

        2.1).不传、null、undefined,函数的this指向window对象(在不严格模式下,this指向window;严格模式下,对应的this指向undefined、null、undefined)

    function A(){console.log(this)} // 不严格模式下
    A.call() // window
    A.call(null) // window
    A.call(undefined) // window
    
    function B(){"use strict"; console.log(this)} // 严格模式下
    B.call() // undefined
    B.call(null) // null
    B.call(undefined) // undefined

        2.2).传入数值、字符串、布尔值等基础类型,this指向对应的包装类型Number、String、Boolean

        2.3).传入函数名,this指向这个函数的引用

    A.call( B ) // function B(){"use strict"; console.log(this) }

        2.4).传入对象,this指向这个对象(最常用)

      3.使用场景

        3.1)一个容易犯错的例子

    function add(x,y){
        console.log( x+y )  
    }
    function sub(x,y){
        console.log( x-y )
    }
    add.call( sub, 8, 6 )  // 14
    // 执行的是add函数,只不过add函数中this指向了sub函数

        3.2)改变this的指向(常用)

    var name = "hi!"
    var obj = {name:"hello!"}
    function A(){console.log(this.name)}
    A() // "hi!"
    A.call(obj) // "hello!"

        3.3) 继承(常用)

    function Person(id,name){
        this.id = id;
        this.name = name;
    }
    function Student(id,name,grade,score){
        Person.call(this,id,name) // 使用call()完成继承
        this.grade = grade;
        this.score = score;
    }
    
    var stu = new Student('123','Jame','grade 2','98') 

    二,apply()

      apply 和 call 使用基本相同,仅仅是参数传递不同;call() 参数一个一个传;apply() 传递的是一个数组;

      当传递参数个数已知时,使用call();如果参数不定,使用apply();

      用法:

        apply(obj,[arg1,arg2,...])

      例题:

        1.自定义log()函数,模拟console.log()函数;

          分析:

            1.1)console.log()函数,可以传递多个不同类型的参数;通过自定义函数简单模拟console.log()可以这样做:

             function log(arg){ console.log(arg) }

             但是这样有个问题,只能传递一个参数,多个参数怎么办?

            2.1) 由于多个参数就涉及到arguments对象,可以将log()改装成:

             function log(){ console.log(arguments) }

             这样还不行,console.log()会把arguments直接打印出来;

                 此时的arguments仅仅是console.log()函数中arguments对象的arguments[0];

             如果想按照console.log()方式打印出来,必须将log()的arguments传值给console.log()函数的arguments对象;

           正确方式如下:

    // 只能使用apply
    function log(){
        console.log.apply(console,arguments)
    }
    
    // 不能使用call函数,否则console.log()函数仍然会把 log()函数的arguments对象当成自身arguments[0]

    三,bind()

      函数绑定bind是ES5中新增的,IE6,7,8不支持;

      bind绑定对象后不会立即执行,而是返回一个函数,以便特定情况下使用;这个技巧大量的用在回调函数、事件处理程序中;

      1.事件处理程序中的this指向

        DOM元素绑定事件后,事件处理程序中this默认情况下指向DOM元素;(IE8 默认指向window)

        如果要使用别的对象中的方法,就必须使用bind()进行绑定

    var handler = {
        name: "Hello world",
        handClick: function(event){
            console.log( this.name )
        }
    }
    document.getElementById('demo').addEventListener('click',handler.handClick); 
    // 输出undefined,DOM绑定后的函数handClick中的this指向DOM元素;而this中不包含name

        如果要想输出handler对象中的name,需要使用bind绑定该对象

    document.addEventListener('click',handler.handClick.bind(handler))

      2.回调函数中的this指向,常见的定时器

        在定时器中,回调函数中的this默认指向window;

        经常需要在定时器的回调函数中使用别的对象中的属性、方法,解决的办法有三种:1.新建一个中间变量  2.bind绑定  3.ES6中的箭头函数 ,最常用的是bind、ES6箭头函数

    var obj = {
        msg:"Hello world",
        getInfo: function(){
            setTimeout(function(){console.log(this.msg)},0) // this->window ,输出undefined
         
            // 1.使用中间变量that
            var that = this;
            setTimeout(function(){console.log(that.msg),0}) // that->obj,输出"Hello world"
    
            // 2.使用bind
            setTimeout(function(){console.log(that.msg).bind(obj),0}) // this->obj,输出"Hello world"
    
           // 2.使用ES6箭头函数,箭头函数中的this指向定义这个函数时所在的对象
           setTimeout(() => {console.log(this.msg)},0}) // this->obj,输出"Hello world"
        }
    
    }    

      bind函数的应用场景基本就是回调函数、事件处理程序;

      如何实现bind()函数?(绑定一个上下文,并返回绑定了这个上下文的函数)

    function bind(fn,context){
        return function(){
            return fn.apply(context,arguments)
        }
    }

    参考:(感谢以下文档)

    [1] 理解call、apply、bind
    [2] 《JavaScript高级程序设计(第3版)》

  • 相关阅读:
    Spark笔记
    java.lang.ClassNotFoundException: org.apache.storm.topology.IRichSpout
    异常分类
    手动调用run方法和普通方法调用没有区别
    URI is not registered ( Setting | Project Settings | Schemas and DTDs )
    谷歌浏览器远程计算机或设备将不接受连接解决方法
    模块2复习
    day09作业01用户登录与验证
    022测试对文档进行读取与写入
    0221判断登录是否成功小程序
  • 原文地址:https://www.cnblogs.com/RocketV2/p/6734910.html
Copyright © 2011-2022 走看看