Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/466.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Function.bind.bind(Function.call)是如何未经修改的?_Javascript_Functional Programming_This_Function Binding - Fatal编程技术网

Javascript Function.bind.bind(Function.call)是如何未经修改的?

Javascript Function.bind.bind(Function.call)是如何未经修改的?,javascript,functional-programming,this,function-binding,Javascript,Functional Programming,This,Function Binding,我的代码库中有这一行: var uncurryThis = Function.bind.bind(Function.call); 我正在努力解决的问题。据推测,它没有结婚。我该如何解决这个问题 我猜这是函数的一个版本。bind它自己的这个被绑定到函数。call。这对我帮助还不够。而且我还没有找到任何用途,所以我甚至不确定你是单独调用它还是需要调用它“作为一种方法”,只是,你知道,先绑定它。它将调用函数传递给绑定函数,而绑定函数本身就是this的值。因此,您将得到一个围绕bind函数的包装器,该

我的代码库中有这一行:

var uncurryThis = Function.bind.bind(Function.call);
我正在努力解决的问题。据推测,它没有结婚。我该如何解决这个问题


我猜这是
函数的一个版本。bind
它自己的
这个
被绑定到
函数。call
。这对我帮助还不够。而且我还没有找到任何用途,所以我甚至不确定你是单独调用它还是需要调用它“作为一种方法”,只是,你知道,先绑定它。

它将
调用
函数传递给
绑定
函数,而
绑定
函数本身就是
this
的值。因此,您将得到一个围绕
bind
函数的包装器,该包装器在调用
this
函数时将其安排为
call
函数。反过来,这是一个函数,它允许您在
调用
函数周围创建一个包装器,该函数绑定到您传递给它的某个参数

如果你今早醒来后没有不停地喝咖啡,一步一步:

  • Function.bind.bind
    是对
    bind
    函数的引用。该引用是由一个属性生成的,该属性为-mission point 1-
    bind
    函数本身。请记住,
    bind
    函数在使用某个函数作为对象调用时,用于在该函数周围创建一个包装器,并将
    this
    绑定到传入的第一个参数
  • 因此,该函数调用将返回一个函数。该函数的工作方式与调用
    function.call.bind(某物)
    类似
  • 如果您将某个随机函数作为参数传递给该函数,那么您将得到一个围绕该随机函数的包装器,该包装器在被调用时的作用类似于
    randomFunction.call(无论什么)
因此:

最重要的一点是:你有一个函数,在函数中有一个代码,它期望
this
有一些属性,它以某种方式使用
this
。你真的希望能够在这里和那里的某个对象上使用这个函数。很明显,你可以用它来做

random.call(someObject);
但是这种神奇的“绑定调用”技巧为您提供了一种廉价的方法,可以在函数上创建变体,从而避免显式编码调用
.call()
。它还允许您在高级前端开发人员职位上多呆一段时间

编辑-我要破坏上面的妙语,因为我刚刚想到了一个很好的理由,可以使用bind+call技巧来获得一个函数,该函数安排对某个期望通过
this
在某个“所有者”对象上运行的函数进行调用。假设您有一个字符串数组,并且希望得到这些字符串的小写版本。你可以这样写:

var uc = ["Hello", "World"];
var lc = uc.map(function(s) { return s.toLowerCase(); });
但有了神奇的“bb”功能,我们还可以写:

var uc = ["Hello", "World"];    
var tlc = bb(String.prototype.toLowerCase);
var lc = uc.map(tlc);
用这种方式编写的改进并不多,但如果要为所有方便的字符串原型方法制作一组
bb()
-ified包装,可能会更有意义。当然,任何东西都有价格,这种包装器可能会对性能产生一些影响。(如果这样的做法很普遍,那么运行时可能会得到改进。)

好的。你知道这是什么吗?这是一种函数的方法,用于修复其
参数,并返回一个新函数。可以简化为:

function bind(context) {
    var fn = this;
    return function() {
        return fn.apply(context, arguments);
    };
}
我将以一种更具功能性的风格使用上下文缩写函数调用,并使用大量的部分应用程序:bindfn(context)->fncontext。带参数:(bindfn(context))(…)等于fncontext(…)

类似地,它接受一个
this
值,但不是返回一个函数,而是立即应用它:callfn(context,…)->fncontext(…)

现在让我们来看看您的代码:
bind.call(bind,call)
。在这里,您将在
bind
上应用
bind
,并将
call
作为此值:bindbind(call)。让我们将此(使用上述规则)扩展为bindcall。如果我们现在提供了一些参数呢

bindbind(调用)(fn)(上下文…)

bindcall(fn)(上下文…)

调用fn(上下文,…)

上下文(…)

一步一步,我们可以做到

uncurryThis=bindbind(call)
/
bindcall

func=uncurryThis(方法)
/
callmethod

结果=func(上下文,…)
/
methodcontext(…)

这方面的一个实际用例是假定转换为静态函数的任何“类”方法,将对象(调用该方法的对象)作为第一个参数:

var uncurryThis = Function.bind.bind(Function.call);
var uc = uncurryThis(String.prototype.toUpperCase);
uc("hello") // in contrast to "hello".toUpperCase()
如果您不能进行方法调用,但需要一个静态函数,那么这会很有帮助;e、 g.如在

["hello", "world"].map(uc) // imagine the necessary function expression
此外,要调用的方法可能不是对象本身的方法,如中所示

var slice = uncurryThis(Array.prototype.slice);
slice(arguments) // instead of `Array.prototype.slice.call(arguments)` everywhere

如果有帮助,这里还有一个显式实现,没有任何绑定:

function uncurryThis(method) {
    return function(context/*, ...*/)
        return method.apply(context, Array.prototype.slice.call(arguments, 1));
    };
}

当我们对函数调用bind时,它返回一个新函数,该函数由上下文替换:

function random() {
  alert(this.foo);
}
var newRandom = random.bind({foo:"hello world"}) //return new function same as //`random` with `this` is replaced by object {foo:"hello world"}
同样,我们有:

Function.bind.bind(Function.call)
// return new Function.bind with its `this` is replaced by `Function.call`
它有以下来源(使用@Bergi提供的
bind
函数的简化版本):

请注意,这里的上下文是函数,例如
random
,因此我们将bb(random)称为
newRandom
函数:

newRandom = function(){
   return Function.call.apply(random, arguments); //also replace 
}
//`apply` function replace `this` of Function.call to `random`, and apply Function(now become `random`) with arguments in `arguments` array.

我认为如果你倒转过来,这可以解释得更清楚

上下文:

假设我们要将字符串数组小写。可以这样做:

[‘A’, ‘B’].map(s => s.toLowerCase())
比如说,不管出于什么原因,我想让这个电话更通用。我不喜欢
s
如何绑定到
this
,胖箭头被绑定到
toLowerCase()

这个怎么样

[‘A’, ‘B’].map(String.prototype.toLowerCase)
这不起作用,因为
map
将元素作为第一个参数传递,但
String.prototype.toLowerCase
不接受任何参数。它希望输入字符串作为
this
传递

所以问题是我们能创建一个
包装器
fu吗
[‘A’, ‘B’].map(s => s.toLowerCase())
[‘A’, ‘B’].map(String.prototype.toLowerCase)
[‘A’, ‘B’].map(wrapper(String.prototype.toLowerCase))
instance.function(...args)
=== (instance.constructor.prototype).function.call(instance, ...args)
=== (Class.prototype).function.call(instance, ...args) [1]
=== (Class.prototype).function.bind(instance)(...args) [2]
Class === String
instance === 'STRING'
function === toLowerCase
args === []
---
'string'.toLowerCase()
=== ('STRING'.constructor.prototype).toLowerCase.call('STRING')
=== (String.prototype).toLowerCase.call('STRING')
=== (String.prototype).toLowerCase.bind('STRING')()
'string'
=== (wrapper)(String.prototype.toLowerCase)('STRING')
=== (uncurryThis)(String.prototype.toLowerCase)('STRING')
=== (Function.bind.bind(Function.call))(String.prototype.toLowerCase)('STRING')

// Function.bind is not really the generic form because it's not using the prototype
// Here Function is an instance of a Function and not the constructor.prototype
// It is similar to calling Array.bind or someFunction.bind
// a more correct version would be
// someFunction.constructor.prototype.bind === Function.prototype.bind, so
=== (Function.prototype.bind.bind(Function.prototype.call))(String.prototype.toLowerCase)('STRING')

// Apply formula 2
// instance.function(...args) === (Class.prototype).function.bind(instance)(...args) [2]
// Class === Function
// function === bind
// instance === Function.prototype.call
// ...args === String.prototype.toLowerCase
=== instance.function(...args)('STRING')
=== (Function.prototype.call).bind(String.prototype.toLowerCase)('STRING')

// Apply formula 2 again
// Class == Function
// function == call
// instance === String.prototype.toLowerCase
// ...args === 'STRING'
=== instance.function(...args)
=== (String.prototype.toLowerCase).call('STRING')

// Apply formula 1
instance.function(...args) === (Class.prototype).function.call(instance, ...args) [1]
// Class === String
// function === toLowerCase
// instance === 'STRING'
// args === []
=== instance.function(...args)
=== 'STRING'.toLowerCase(...[])
=== 'STRING'.toLowerCase()

// So we have
(wrapper)(String.prototype.toLowerCase)('STRING')
=== (uncurryThis)(String.prototype.toLowerCase)('STRING')
=== 'STRING'.toLowerCase()
=== 'string'
'STRING'.toLowerCase()
=== (String.prototype.toLowerCase).call('STRING') // apply formula [1]
=== (Function.prototype.call).bind(String.prototype.toLowerCase)('STRING') // apply formula [2]

// At this point, you might wonder why `uncurryThis !== (Function.prototype.call).bind)
// since it also takes (String.prototype.toLowerCase)('STRING')
// This is because passing in (Function.prototype.call).bind) as an argument
// is the same as passing in Function.prototype.bind
// `this` binding isn't done unless you call
// (Function.prototype.call).bind)(String.prototype.toLowerCase)
// at that exact moment.
// If you want to be able to pass unCurryThis as a function, you need to bind the
// Function.prototype.call to the Function.prototype.bind.

=== (Function.prototype.bind.bind(Function.prototype.call))(String.prototype.toLowerCase)('STRING') // apply formula 2
=== (Function.bind.bind(Function.call))(String.prototype.toLowerCase)('STRING') // un-generic-ize
=== (uncurryThis)(String.prototype.toLowerCase)('STRING')
=== (wrapper)(String.prototype.toLowerCase)('STRING')

=>

unCurryThis === wrapper === Function.bind.bind(Function.call)