apply、call、bind的详解

一:作用(与函数有关)

改变函数运行时的上下文

函数有定义时上下文运行时上下文上下文可以改变的概念

二:call和apply的区别

call接收的是一个一个的参数
apply接收的是数组
当传入的参数个数不确定时,用apply

三:一堆栗子

栗子1

function Fruits(){}
Fruits.prototype = {
    color:'red',
    sayColor:function(){
        console.log("color is:"+this.color)
    }
}

let apple = new Fruits();
apple.sayColor();  // red

这里有一个banana,但是我们不想给香蕉重复定义sayColor方法,就可以借用apple的,也就是改变了this

banana = {
    color : 'yellow'
}
apple.sayColor.call(banana)

例子2

let func = function(arg1,arg2){}
func.call(this,arg1,arg2);
func.apply(this,[arg1,arg2]);
// 这里的this是你想指定的上下文,可以是任何JavaScript对象
// 剩下的参数与你想借用的函数的参数想对应

例子3——巩固apply(数组)

var obj = {
    name : '小美女'
};
function func(first, last){
    console.log(first + ' ' + this.name + ' ' + last);    // a 小美女 b
}
func.apply(obj, ['a','b']);

1. 第一个参数是作为函数上下文的对象 , 这里将obj作为函数的对象,this指向了obj
2. 第二个参数是一个数组,这里数组中的参数分别对应函数的first 和 last
3. 将obj对象冒充进去了

例子4——巩固call(一个一个的参数)

var obj = {
    name : '小美女'
};
function func(first, last){
    console.log(first + ' ' + this.name + ' ' + last);  // a 小美女 b
}
func.call(obj, 'a', 'b');

1. 第一个参数是作为函数上下文的对象 , 这里将obj作为函数的对象,this指向了obj
2. 第二个到第n个参数分别对应函数的参数们
3. 将obj对象冒充进去了  

四:几个常考的例子

  1. 求数组的最大值和最小值
/*
* 获取数组的最大值和最小值
* Math.max(a,b,c...):一组数的最大值
* Math.min(a,b,c...):一组数的最小值
*
* 这两个函数对于数字组成的数组没法用
* 使用apply传入数组后,等于使用数组中的所有值作为函数的参数
*
* nums数组本身没有max和min方法,但是Math有此方法,所以借助call和apply来计算
* */
方法一:借助Math的max和min方法
let nums = [100,20,-199,33];
let maxNum = Math.max.apply(null,nums);
let minNum = Math.min.apply(null,nums);
console.log(maxNum);    // 100
console.log(minNum);    // -199

方法二:es6的扩展运算符
console.log(Math.max(...nums)); // 100
console.log(Math.min(...nums))  // -199
  1. 变量的类型
Object.prototype.toString.call(arr)

为什么用toString方法:
因为object.toString()的原型中是返回数据类型的,但很多实例中都改写了这一方法

let arr = [1,2,3];
// 检验在实例上是否有toString方法
console.log(Array.prototype.hasOwnProperty("toString"));    // true
console.log(arr.toString());    // 1,2,3

delete Array.prototype.toString;
console.log(Array.prototype.hasOwnProperty("toString"));    // false
console.log(arr.toString());    // [object Array]

3.将伪数组转化为真正的数组

// 将伪数组转化为真正的数组,因为伪数组没有slice方法,用此方法后可以将它转化成真正的数组
function toArray(obj){
    return Object.prototype.slice.call(obj)
}

五:bind

bind方法类似于call,会新创建一个函数,称为绑定函数,调用绑定函数时,bind方法传入的第一个参数为this,剩下的参数作为原函数的参数来调用原函数

六:bind call apply比较

/*
* 三者比较
*   在改变上下文后并不是立即执行,就用bind
* */
let oo = {
    x:1
}
let foo = {
    getX : function(){
        console.log(this.x)
    }
}
foo.getX.call(oo);
foo.getX.apply(oo);
foo.getX.bind(oo)()

注意bind后面加了个括号表示执行

七:其他

1. 改变this的指向

var obj = {
    name : "小美女"
};
function fn(){
    console.log(this.name); // 小美女, this指向了object
}
fn.call(obj);   

2. 借用别的对象的方法

var Person1 = function(){
    this.name = '小美女';
}
var Person2 = function(){
    this.getName = function(){
        console.log(this.name); // 小美女
    }
    // console.log(this);   // Person2中所有的
    Person1.call(this); // 使用Person1对象代替this,相当于Person2继承了Person1的属性好方法
}
var person = new Person2(); 
person.getName();
// person 是Person2的一个实例
// person继承了Person2所有的属性和方法getName

3. 调用函数

function abc(){
    console.log('abc');
}
abc.call(); // call和apply都可以用来调用函数,使函数立即执行

你可能感兴趣的:(apply、call、bind的详解)