JavaScript 中call、apply、bind学习

来源:互联网 发布:淘宝怎么更改实名认证 编辑:程序博客网 时间:2024/06/06 17:07

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 方法返回值是上下文为 thisArgfunc

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

var someuser = {    name: 'monoplasty',    func: function() {        console.log(this.name);    }};var foo = {    name: 'foobar'};foo.func = someuser.func;foo.func(); // 输出 foobarfoo.func1 = someuser.func.bind(someuser);foo.func1(); // 输出 monoplastyfunc = someuser.func.bind(foo);func(); // 输出 foobarfunc2 = func;func2(); // 输出 foobar

上面代码直接将 foo.func 赋值为 someuser.func,调用 foo.func()时,this指针为 foo,所以输出结果是 foobarfoo.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 javascriptmonoplastyLoves = 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(); // 输出 foobarfunc2 = 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.funcbind 方法的实现,函数体内 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 是没有效果的。

原创粉丝点击