![](/img/trans.png)
[英]JavaScript - I don't understand how this collision detection function works
[英]I can't understand how this javascript function works
我正在閱讀bind的函數定義 ,但我無法100%理解編寫的代碼:
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP
? this
: oThis || window,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
具體來說,我沒有達到fNOP
的目的,我不明白為什么需要設置fBound
的原型。 我也掛在fToBind.apply
部分(我無法弄清楚這在這個上下文中代表什么)。
有人可以解釋這里發生了什么嗎?
好吧,需要設置fBound
原型的一個原因是,在函數上調用bind
的結果bind
該函數具有相同的原型。 這也是fNop
似乎進來的地方 - 它允許你使用new fNop()
設置fBound
的原型而不調用可能有副作用的原始函數。
對apply
的調用允許您在函數中設置this
並指定其他參數。 由於bind
允許你“curry”函數的參數,你必須結合綁定函數時傳入的參數和調用它的參數。
這是為了確保
instanceof
) new g()
繼承自f
的原型鏈。 (因此.prototype = new fNop
部分) 例:
function f() {
this.foo = 'bar';
}
f.prototype = {
baz: 'yay!'
};
var g = f.bind({});
var o = new g();
console.log(o.foo); // 'bar' - (1)
console.log(o.baz); // 'yay!' - (2)
在你調用new g()
的那一刻, fBound
函數被稱為一個fBound
,它有一個全新的對象對象( this
),它是fNop
一個實例。
ECMAScript5標准定義了一種用於綁定功能的復雜算法。 除其他外,以下斷言必須成立:
var DateJan2042 = Date.bind(null, 2042, 0);
/*1*/ console.assert(Function.prototype.bind.length == 1, 'bind should have a length of 1');
/*2*/ console.assert(typeof DateJan2042 == 'function', 'bind() should return a function');
/*3*/ console.assert(!DateJan2042.hasOwnProperty('prototype'), 'Bound function must not have a prototype');
/*4*/ console.assert(DateJan2042.length == Math.max(Date.length - 2, 0), 'Bound function should have a proper length');
/*5*/ console.assert(typeof DateJan2042() == 'string', 'Function call should return a string');
/*6*/ console.assert({}.toString.call(new DateJan2042()).indexOf('Date') != -1, 'Constructor call should return a new Date object');
/*7*/ console.assert(new DateJan2042() instanceof DateJan2042, 'Instanceof check should pass for constructor\'s return value');
/*8*/ console.assert((new DateJan2042()).getMonth() == 0, 'Constructor should be called with bound arguments');
/*9*/ console.assert((new DateJan2042(1)).getDate() == 1, 'Constructor should take additional arguments');
/*10*/ console.assert(!/^function *\( *[^ )]/.test(Function.prototype.toString.call(DateJan2042)), 'Bound function should have no formal arguments');
由於正確綁定的函數不是真正的Function
對象,因此使用polyfill(特別是數字2/3和4/10)是不可能完成的,但您可以嘗試盡可能多地實現。
有問題的實現試圖通過掛鈎原型鏈來解決6號和7號問題,但這還不夠 。
這是一個更好的替代實現,但仍然不完美: http : //jsfiddle.net/YR6MJ/
// check to see if the native implementation of bind already
// exists in this version of JavaScript. We only define the
// polyfill if it doesn't yet exist.
if (!Function.prototype.bind) {
// creating the bind function for all Function instances by
// assigning it to the `Function.prototype` object. Normally
// you would avoid assigning to builtin prototypes because you
// may cause a conflict with new features, but here this is a
// known feature that is already in the spec that we're adding
// to a JavaScript runtime that is not up to spec, so its ok
Function.prototype.bind = function (oThis) {
// if you attempt to call this function from a non-function object
// for example if you assign this bind function to a normal object
// or use `call`/`apply` to change the context of this function call to
// a non function value (e.g. `Function.prototype.bind.call({})`), we
// throw an error because bind can only work on functions, and we
// require that `this` in this call is a function
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
// bind does two things, it binds a context (`this` value) to a
// function for when its called, and it provides a way to bake in
// some pre-defined arguments that are automatically passed into
// that function when called. Those arguments can be passed into
// the bind call and get picked up here as `aArgs` pulling them
// from `arguments` making sure to lop off the `oThis` value
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this, // this is the function we're binding
fNOP = function () {}, // a constructor used for `new` usage (see below)
// `fBound` is the bound function - the result that bind is going to
// return to represent the current function (`this` or `fToBind`) with
// a new context. The idea behind this function is that it will simply
// take the original function and call it through `apply` with the
// new context specified.
fBound = function () {
// call the original function with a new context using `apply`.
// however if the function is called with `new`, it needs to be called
// with the context of, and return, a new object instance and not the
// bound version of this. In that case, binding gets ignored in favor
// of using the `this` of the new instance rather than the `oThis` binding.
// new object instances inherit from the prototype of their constructors.
// Our `fBound` function is supposed to mimic the original with the
// exception of a change in context. So if new objects are created with
// it, they should behave as though they were created from the original.
// But at the same time, we can't simply carry over the prototype of the
// original into `fBound` because it is a separate function and needs its
// own prototype, just one that also inherits from the original. To
// accommodate this, the `fNOP` function (constructor) above is used as
// an intermediary for creating `fBound`'s prototype while allowing it to
// be unique but also inherit the original. And because that becomes part
// of the bound function's prototype chain, it can be used to determine
// whether `this` in `fBound` is an instance created by `new` or not since
// `instanceof` works through a prototype chain lookup.
return fToBind.apply(this instanceof fNOP
? this
: oThis,
// call the function with arguments that include the added
// arguments specified from the original bind call plus
// the arguments this function was called with
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// `fNOP`'s use to provide an intermediary prototype between `fBound` and
// the current function instance mimics `Object.create`. But we're assuming
// if you don't have `bind`, you probably don't have `create` either, so do
// it the old fashioned way with a constructor. This works by setting the
// constructor's prototype to the to-inherit-from constructor's (this)
// prototype. A check is needed to prevent assinging that prototype to null
// if it doesn't exist on this function (Function.prototype is technically
// a valid target for `bind()` because it is a function but one that does not
// have its own prototype).
if (this.prototype) {
fNOP.prototype = this.prototype;
}
// here the inheritance is made. As a new function, `fBound` has no existing
// inheritance chain to worry about, so we can easily replace it with a new
// one - that of a new instance `fNOP`. Since `fNOP`'s prototype is the original
// function's prototype, `fBound` has a prototype which directly inherits from
// that, one level between new instances and the original prototype. So
// `fBound.prototype.__proto__ === this.prototype` and new instances of `fBound`
// created with `new fBound()` will inherit from `fBound.prototype` as well as
// the original function's prototype.
fBound.prototype = new fNOP();
// return the bound version of the function as
// the result of the bind call
return fBound;
};
}
從早先的評論:
而不是使用fNop,為什么你不能只說
fBound.prototype = this.prototype
?
據我所知,主要區別在於當綁定函數內的this
值是調用bind
的原始函數的實例時,則綁定到的值 - 最初傳遞給bind
的第一個參數 - - 被忽略了。
例如,這段代碼:
function Test(blah) {
console.log(this.length, blah);
}
Test.prototype.length = 77;
Test.prototype.fn = Test.bind(['a', 'b', 'c'], "testing");
new Test().fn()
...導致fn
打印:
77 testing
換句話說,價值this
里面fn
是Test
在它被調用的實例。 您的建議將提供綁定數組到apply
inside bind
,因此,以這種方式編寫,相同代碼的最后一行將打印:
3 testing
我並不完全清楚為什么這很重要,但它確實強調了你的建議不會產生相同的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.