ワン❀リード
最近angularjsソースコードを見て同僚、ソースコードは、バインドの多様で、混乱を取得適用され、彼は、私に尋ねたあなたは違いが、適用呼び出し、それをバインド知っていますか?私はそれが関数呼び出しで言うとも異なるバインドを実行します。このメソッドを指定し、アプリケーションを適用し、それはこの結合のための唯一の責任があり、新しいメソッドを返し、実行されません。
彼は、オブジェクトがオブジェクトcを結合し、その後、オブジェクトbを結合し、そして最終的にバインドする方法であれば、この時間はこのファンクションポイントを実行することを、尋ねましたか?(彼はしばしば...この素晴らしい質問を);私は、思考せずに答え、それはCであり、本当ですか?彼はに尋ねました。
瞬間を尋ねられて、私は私が間違っている必要があります知っている、私は確かに、小さなデモ検証を書き留めたので、私は三つの方法の下で細部の違いを理解する必要性を感じています。
せO1 = { : 1 }。 せO2 = { : 2 }。 せO3 = { : 3 }。 関数FN(B、C){ にconsole.log(この.A)。 }。 FN1ましょう = fn.bind(01)を、 FN2ましょう = fn1.bind(O2)を、 FN3ましょう = fn2.bind(O3)を、 FN3()// ?
II❀関数呼び出しと関数適用
我々は2つの方法で機能の実装は、1が共通の関数呼び出しであることを知って、第二の機能が適用されます。
関数呼び出しを説明するためのアクティブ - パッシブ関係から、より受動的であり、かつ機能アプリケーションは、それが非常に活発であり、我々は例を見て:
VaRの名= "風が風で聞く" 、 OBJ = { 名称: 'エコー' }; 関数のFn(){ にconsole.log(この.nameの); }; // 関数呼び出し のFn()// 風が風である聞きます / / 機能アプリケーション fn.call(OBJ); // エコー
FN())(window.fnと同等である SE FNは、ウィンドウを呼び出したので、これは、ウィンドウを指し、それは古代の子の結婚のようなものだ、結婚のこの分かりやすく、そしてない自由のために、FNのために配置されています。
fn.call() 、同等ですが、(window.fn.call)が、FNへの呼び出しは、これを変更する機会を提供し、この時点で、これはオブジェクトobjです。それは、心の解放とみなすことができ、FN結婚、より多くの自由と幸福を選択する権利を持っています。
機能をより柔軟に実行したとき、あなたは、理解機能は、アプリケーションの方法を提供することにある()(呼び出し)と適用すべきだと言って、彼らはこのポイントを作ります。
トリプル❀コールと適用
私たちは、コールの使用ということを知っていると適用、およびこれらの2つの方法ということ、それはどのような違いを生むん機能アプリケーションの視点に立ち、実際には、違いがパラメータを渡すの少し違った方法です。
call方法中接受的是一个参数列表,第一个参数指向this,其余的参数在函数执行时都会作为函数形参传入函数。
fn.call(this, arg1, arg2, ...);
而apply不同的地方是,除了第一个参数作为this指向外,其它参数都被包裹在一个数组中,在函数执行时同样会作为形参传入。
fn.apply(this, [arg1, arg2, ...]);
除此之外,两个方法的效果完全相同:
let o = { a: 1 }; function fn(b, c) { console.log(this.a + b + c); }; fn.call(o, 2, 3); // 6 fn.apply(o, [2, 3]); //6
肆 ❀ 关于bind
bind之所以要拿出来单独说,是因为它与call,apply又存在一些不同。call与apply在改变this的同时,就立刻执行,而bind绑定this后并不会立马执行,而是返回一个新的绑定函数。
let o = { a: 1 }; function fn(b, c) { console.log(this.a + b + c); }; let fn1 = fn.bind(o, 2, 3); fn1();//6
还记得文章开头我同事提的问题吗,我之所以觉得bind多次后执行,this会指向最后一次bind的对象,是因为没能正确理解bind返回函数的含义。
尝试打印返回的新函数fn1,可以看到它并不是一个普通的function,而是一个bound function,简称绑定函数:
它的TargetFunction指向了bind前的的函数,BoundThis就是绑定的this指向,BoundArgs便是传入的其它参数了。
当我们执行fn1时,就有点类似于TargetFunction.apply(BoundThis,BoundArgs)。
我们可以得出一个结论,当执行绑定函数时,this指向与形参在bind方法执行时已经确定了,无法改变。
let o1 = { a: 1 }; let o2 = { a: 2 }; function fn(b, c) { console.log(this.a + b + c); }; let fn1 = fn.bind(o1, 2, 3); //尝试再次传入形参 fn1(4, 4); //6 //尝试改变this fn1.call(o2); //6
其实很好理解,当执行fn1时,本质上等于window.fn1(),如果this还能被改变,那this岂不是得指向window,那bind方法就没太大意义了。
伍 ❀ 应用
说到这,我们大概知道了这三个方法的作用与区别,那这三个方法有啥用?其实很常用。
我们都知道Math.max()方法能取到一组数字中的最大值,比如:
Math.max(1, 10); //10 Math.min(1, 10); //1
那我们如何利用此方法求数组中最大最小呢,这里就可以利用apply的特性了:
Math.max.apply(null, [1, 2, 10]); //10 Math.max.min(null, [1, 2, 10]); //1
在非严格模式下,当我们让this指向null,或者undefined时,this本质上会指向window,不过这里的null就是一个摆设,我们真正想处理的其实是后面的数组。
还记得在考虑兼容情况下怎么判断一个对象是不是数组吗?再或者是不是一个函数?利用Object.prototype.toString()结合call方法就能解决这个问题:
let a = []; let b = function () {}; Object.prototype.toString.call(a) === "[object Array]";//true Object.prototype.toString.call(b) === "[object Function]";//true
陆 ❀ 总
那么到这里,我们一起理解了我同事提出的奇葩问题,为何bind多次后执行,函数this还是指向第一次bind的对象。
其次,除了函数调用,我们理解了函数应用的概念,也知道如何使用call和apply去实现一个函数应用,顺便通过bind还知道了绑定函数(bound function)的概念。
所以到这里,你知道call、apply与bind的区别了吗?