天天看点

JavaScript 中call、apply、bind学习JavaScript 中call、apply、bind学习

JavaScript 中call、apply、bind学习

Array.find(function(v,i,arr),thisArgs}

数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。

- v:数组值

- i:索引

- arr:当前数组

- thisArgs:fn函数中this指向

Array.filter(fn(v,i),thisArgs)

过滤,返回数组中的满足回调函数中指定的条件的元素。

Array.map(fn(v,i),thisArgs)

对数组的每个元素调用定义的回调函数并返回包含结果的数组。

Array.every(fn(v,i),thisArgs)

数组的所有成员是否满足指定的测试

Array.some(fn(v,i),thisArgs)

只要数组的一个值满足指定的测试,就返回true

- thisArgs: fn方法中this指向,如果是object类型正常指向,如果是string类型,会按fn中的i去截取string中对位的位置的字符

bind,call,apply

  • var slice = Function.prototype.call.bind(Array.prototype.slice);
var Dog=function(){
    this.name="汪星人";
    this.shout=function(){
        alert(this.name);
    }
};

var Cat=function(){
    this.name="喵星人";
};
var dog=new Dog();
var cat=new Cat();
dog.shout();

dog.shout.call(cat); // 执行dog.shout方法,指定cat的环境
cat.shout();
           

call函数

  • 简单的理解:把a对象的方法应用到b对象上(a里如果有this,会指向b);
  • 比较

call 和 apply 的功能是一致的,两者细微的差别在于 call 以参数表来接受被调用函

数的参数,而 apply 以数组来接受被调用函数的参数。call 和 apply 的语法分别是:

func.call(thisArg[, arg1[, arg2[, ...]]])
func.apply(thisArg[, argsArray])
           

其中,func 是函数的引用,thisArg 是 func 被调用时的上下文对象,arg1、arg2 或

argsArray 是传入 func 的参数。我们以下面一段代码为例介绍 call 的工作机制:

var someuser = {
    name: 'monoplasty',
    display: function(words) {
        console.log(this.name + ' says ' + words);
    }
};

var foo = {
    name: 'foobar'
};

someuser.display.call(foo, 'hello'); // 输出 foobar says hello
           

用 Node.js 运行这段代码,我们可以看到控制台输出了 foobar。

someuser.display

是被调用的函数,它通过 call 将上下文改变为 foo 对象,因此在函数体内访问

this.name

时,实际上访问的是

foo.name

,因而输出了foobar。

bind函数

call函数和apply函数功能一样,区别是第二个参数形式不一样,call传递多个参数,任意形式(传入参数和函数所接受参数一一对应),apply第二个参数必须是数组形式,如a.call(b,2,3); ==> a.apply(b,[2,3]);

可以使用 bind 方法来永久地绑定函数的上下文,使其无论被谁调用,上

下文都是固定的。bind 语法如下:

func.bind(thisArg[, arg1[, arg2[, ...]]])
           

其中 func 是待绑定函数,thisArg 是改变的上下文对象,arg1、arg2 是绑定的参数表。

bind 方法返回值是上下文为

thisArg

func

通过下面例子可以帮你理解 bind 的使用方法:

var someuser = {
    name: 'monoplasty',
    func: function() {
        console.log(this.name);
    }
};

var foo = {
    name: 'foobar'
};

foo.func = someuser.func;
foo.func(); // 输出 foobar

foo.func1 = someuser.func.bind(someuser);
foo.func1(); // 输出 monoplasty

func = someuser.func.bind(foo);
func(); // 输出 foobar

func2 = func;
func2(); // 输出 foobar
           

上面代码直接将

foo.func

赋值为

someuser.func

,调用

foo.func()

时,this指针为

foo

,所以输出结果是

foobar

foo.func1

使用了 bind 方法,将

someuser

作为this指针绑定到

someuser.func

,调用 foo.func1() 时,this指针为

someuser

,所以输出结果是

monoplasty

。全局函数

func

同样使用了 bind 方法,将

foo

作为 this 指针绑定到

someuser.func

,调用

func()

时,this 指针为

foo

,所以输出结果是

foobar

。而

func2

直接将绑定过的

func

赋值过来,与

func

行为完全相同。

使用 bind 绑定参数表

bind 方法还有一个重要的功能:绑定参数表,如下例所示。

var person = {
    name: 'monoplasty',
    says: function(act, obj) {
        console.log(this.name + ' ' + act + ' ' + obj);
    }
};

person.says('loves', 'javascript'); // 输出 monoplasty loves javascript

monoplastyLoves = person.says.bind(person, 'loves');
monoplastyLoves('you'); // 输出 monoplasty loves you
           

可以看到,

monoplastyLoves

将 this 指针绑定到了

person

,并将第一个参数绑定到

loves

,之后在调用

monoplastyLoves

的时候,只需传入第二个参数。这个特性可以用于创建一个函数的“捷径”,之后我们可以通过这个“捷径”调用,以便在代码多处调用时省略重复输入相同的参数。

理解 bind

尽管 bind 很优美,还是有一些令人迷惑的地方,例如下面的代码:

var someuser = {
    name: 'monoplasty',
    func: function () {
        console.log(this.name);
    }
};

var foo = {
    name: 'foobar'
};

func = someuser.func.bind(foo);
func(); // 输出 foobar

func2 = func.bind(someuser);
func2(); // 输出 foobar
           

全局函数

func

通过

someuser.func.bind

将this指针绑定到了

foo

,调用

func()

输出了

foobar

。我们试图将

func2

赋值为已绑定的

func

重新通过

bind

将this指针绑定到

someuser

的结果,而调用

func2

时却发现输出值仍为

foobar

,即 this 指针还是停留在

foo

对象上,这是为什么呢?要想解释这个现象,我们必须了解 bind 方法的原理。

让我们看一个 bind 方法的简化版本(不支持绑定参数表):

someuser.func.bind = function(self) {
    return this.call(self);
};
           

假设上面函数是

someuser.func

bind

方法的实现,函数体内 this 指向的是

someuser.func

,因为函数也是对象,所以

this.call(self)

的作用就是以

self

作为this指针调用

someuser.func

/* 将func = someuser.func.bind(foo)展开: */ 
func = function() {
    return someuser.func.call(foo);
};

 // 再将func2 = func.bind(someuser)展开:
func2 = function() {
    return func.call(someuser);
};
           

从上面展开过程我们可以看出,

func2

实际上是以

someuser

作为

func

的this指针调用了

func

,而

func

根本没有使用 this 指针,所以两次 bind 是没有效果的。

继续阅读