喋喋不休

真正的勇士,胖还贪吃,困还熬夜,穷还追星,丑还颜控

0%

call、apply以及bind

call,apply,bind

在JavaScript中,call、apply和bind是Function对象自带的三个方法,都是为了改变函数体内部 this 的指向。

apply 、 call 、bind 三者第一个参数都是 this 要指向的对象,也就是想指定的上下文;

apply 、 call 、bind 三者都可以利用后续参数传参;

bind 是返回对应 函数,便于稍后调用;apply 、call 则是立即调用 。

1.列子:

function sayHello() {}

sayHello.prototype = {
    name: 'jack',
    say: function () {
        console.log('Hello ' + this.name);
    }
}

var people = new sayHello(); // 此时方法里面的this指的是sayHello
people.say(); // Hello jack

但是如果我们有一个对象 child= {name : ‘lucy’} ,我们不想重新定义 say 方法,那么我们可以通过 call 或 apply 用 apple 的 say 方法:

child = {
    name : 'lucy'
}
people.say.call(child); //此时的this的指向已经同过call()方法改变了,指向的是child,this.name就是child.name='lucy';
//结果是Hello lucy 

people.say.apply(child);//同理,此时的this的指向已经同过apply()方法改变了,指向的是child,this.name就是child.name ='lucy';
//Hello lucy

// 如果传入的是 null:
people.say.apply(null); // null是window下的,此时,this 就指向了window ,但是window下并没有name这个属性,因此this.name就是window.name=undefined;
//Hello undefined

2.对于 apply、call 二者而言,作用完全一样,只是接受 参数 的方式不太一样。call 是把参数按顺序传递进去,而 apply 则是把参数放在数组 里。

var array1 = [12,'foo',{name:'Joe'},-2458];
var array2 = ['Doe' , 555 , 100];

Array.prototype.push.call(array1, array2);
// 这里用 call 第二个参数不会把 array2 当成一个数组,而是一个元素

//等价于array1.push(‘‘'Doe' , 555 , 100’’);
//array1.length=5;

Array.prototype.push.apply(array1, array2); // 这里用 apply 第二个参数是一个数组

// 等价于:  array1.push('Doe' , 555 , 100);
//array1.length=7;

3.类(伪)数组使用数组方法

var divElements = document.getElementsByTagName('div'); //虽然 divElements 有length属性,
但是他是一个伪数组,不能使用数组里面的方法

Array.isArray(divElements);// false

var domNodes = Array.prototype.slice.call(document.getElementsByTagName('div'));
// 将数组对象Array里的this指向伪数组document.getElementsByTagName('div'), 
//slice() 方法可从已有的数组中返回选定的元素,不传参数是,返回整个数组 

Array.isArray(domNodes);// true

4. 验证一个对象的类型可以用:

Object.prototype.toString.call(obj) 

5.bind() 方法,MDN 的解释是:bind() 方法会创建一个 新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind() 方法的第一个参数 作为 this,传入 bind() 方法的 第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

var bar = function(){
    console.log(this.x);
}
var foo = {
    x:3
}

bar(); // undefined
var func = bar.bind(foo); //此时this已经指向了foo,但是用bind()方法并不会立即执行,而是创建一个新函数,如果要直接调用的话 可以 bar.bind(foo)()


func(); // 3

6.在 Javascript 中,多次 bind() 是无效的。

var fun1 = function(){
    console.log(this.x);
}
var fun2 = {
    x:3
}
var fun3 = {
    x:4
}
var func = fun1.bind(fun2).bind(fun3);
func(); //3

var fun4 = {
    x:5
}

var func = fun1.bind(fun2).bind(fun3).bind(fun4);
func(); //3

7.apply、call、bind 三者相比较,之间又有什么异同呢?何时使用 apply、call,何时使用 bind 呢。简单的一个例子:

var obj = {
    name: ‘marry’,
};

var foo = {
    getNmae: function() {
        return this.name;
    }
}
console.log(foo.getNmae.bind(obj)());  //marry
console.log(foo.getNmae.call(obj));    //marry
console.log(foo.getNmae.apply(obj));   //marry

bind只是返回对应的函数,还需要调用才行