call,apply, bind 的区别 和 用法

前言
在js中,函数是对象的方法。如果一个函数不是js的对象的方法,那么它就是全局对象的函数

call,apply, bind都是继承自Function.prototype,当然,普通的对象,函数,数组都继承了Function.prototype对象中的三个方法,所以这三个方法都可以在数组,对象,函数中使用,都是为了改变this的指向,三者第一个参数都是this要指向的对象,也就是想指定的上下文,apply,bind, call三者都可以利用后续参数传参,bind是返回对应的函数,便于稍后调用,apply,call是立即调用

 function Person () {
        // console.log(this);指向当前实例化对象
        this.say = {
            //在构造函数原型上添加属性和方法
            name: '王淼',
            age: 18,
            show: function() {
                console.log(this.age)
            }
        }
    }
    var obj = new Person()
 
  look = {
      age: 19
  }
   构造函数上又一个constructor属性指向当前构造函数,实例化对象的__proto__等于构造函数的原型
   
   但如果我们有一个look: {age: 19},我们想改变age的属性值,而不想定义另一个方法,
   我们可以通过call,apply
    
    obj.say.show.call(look); //19
    obj.say.show.apply(look); //19
    //如果传入的是null;
    obj.say.show.call(null);
    //null是window下的,此时this就指向了window,但是window下没有age属性,
     因此this.a ge就是window.age = undefined
    // 此时的this指向已经通过call()方法改变了,指向look

对于call,apply而言,作用完全一样,只是接受的参数不同,call是把参数按顺序传递进去,第一个参数都是指定函数内部的this即this要指向的对象,如果第一个参数是null, undefined,this或者是不传参,表示函数此时处于全局作用域,第二个参数必须一个一个添加,而apply中必须以数组的形式添加

	   var arr1 = [1, 2, 3, 4, 5];
        var arr2 = [6, 7, 8]
        Array.prototype.push.apply(arr1, arr2)
        console.log(arr1.length)
        //第一个参数是this应该指向那个数组, 这里用call第二个参数不会将arr2当作一个数组,
        而是当作一个元素,所以打印结果为[1, 2, 3, 4, 5, Array(3)],arr1.length = 6,用apply的话,
        第二个参数是一个数组,打印结果为[1, 2, 3, 4, 5, 6, 7, 8],arr1.length = 8;

类(伪)数组使用数组方法
例如:

	var h1 = document.getElementByTagName('h1');
	console.log(Array.isArray(h1)) // false
	虽然h1有length属性,但是它是一个伪数组,不能使用数组里面的方法
	var obj = Array.prototype.slice.call( document.getElementByTagName('h1'))
	//将数组对象array里的this指向伪数组,slice方法可从已有的数组中返回选定的元素,不传参是返回整个数组

验证一个对象 的类型可以用Object.prototype.toString.call(obj) 返回[object object]

bind

	 		var bar = function() {
	            console.log(this.x)
	        }
	        var f = {
	            x: 3
	        }
	        bar(); //undefined,bar函数环境下没有x属性
	        var func = bar.bind(f);
	        func()
	        此时this已经指向了f,但是bind()方法不会立即执行,而是创建一个新函数,如果要直接调用的话可以bar.bind(f)()
	        在js中多次bind()是无效的,更深层次的原因,bind()的实现,相当于使用函数在内部包了一个call/apply,第二次bind()相当于再包一个bind,所以第二次以后的bind是无法生效的

    var bar = function() {
        console.log(this.x) //3
    }
    var f = {
        x: 3
    }
    var n = {
        x: 4
    }
    bar(); //undefined,bar函数环境下没有x属性
    var func = bar.bind(f).bind(n);
    func() // 3

apply, call, bind有何异同

 var obj = {
            x: 80, 
            y: "nihao",
            z: 666
        }
        var f2 = {
            getx: function(name, sex) {
                return this.x + this.y + this.z + name +sex
            }
        }
        console.log(f2.getx.bind(obj)())
        console.log(f2.getx.call(obj))
        console.log(f2.getx.apply(obj))

    console.log(f2.getx.call(obj, "wm", "女"))
    
    console.log(f2.getx.apply(obj, ['zhangsan', "男"]))
    console.log(f2.getx.bind(obj, "lisi", "人妖")())
    console.log(f2.getx.bind(obj)("王五", "变态"))

第一个参数都是this要指向的对象,都是改变this指向的,并且都是Function.prototype中具有的方法, call方法中第二个参数是按顺序一个一个传递与方法中的参数相对应,而apply中的第二个参数必须以数组方式传递参数,数组中的每一个参数与方法中的形参相对应,如果传入的参数不是数组则报错,而bind的第二个参数与call相同,都是按顺序传递的,与之不同的是bind()方法不会立即执行而是返回一个新的函数,所以也可以在调用的时候进行传参

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

web夏目贵志

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值