JavaScript咖喱

mjm*_*che 11 javascript

我是JavaScript的新手,试图从Oreilly JavaScript Cookbook中理解这个关于currying的教程.

有人可以用简单的语言逐步详细解释这个程序.请务必解释在程序的倒数第二行传递的"null"参数.如果您能提供帮助,请提前感谢您.

function curry(fn, scope) {
    scope = scope || window;
    var args = [];
    for (var i = 2, len = arguments.length; i < len; ++i) {
        args.push(arguments[i]);
    }
    return function() {
        var args2 = [];
        for (var i = 0; i < arguments.length; i++) {
            args2.push(arguments[i]);
        }
        var argstotal = args.concat(args2);
        return fn.apply(scope, argstotal);
    };
}

function diffPoint(x1, y1, x2, y2) {
    return [Math.abs(x2 - x1), Math.abs(y2 - y1)];
}

var diffOrigin = curry(diffPoint, null, 3.0, 4.0);
var newPt = diffOrigin(6.42, 8.0); //produces array with 3
Run Code Online (Sandbox Code Playgroud)

Mat*_*ggs 21

如果您不介意建议,请从Javascript:The Good Parts开始.使用Javascript模式或Javascript Ninja的秘密进行更高级的技术.Cookbook更多的是针对问题的罐装解决方案,然后是学习资源.

Matt Ball在解释最新情况方面做得很好.如果你是初学者,我也不会试图弄清楚咖喱功能.除此之外,IMO这种咖喱功能很糟糕.这就是我改变它的方式

// this is doing binding and partial function application, 
// so I thought bind was a more appropriate name
// The goal is that when you execute the returned wrapped version of fn, its this will be scope
function bind(fn, scope) {
  // arguments is an implicit variable in every function that contains a full list
  // of what was passed in. It is important to note that javascript doesn't enforce arity.
  // since arguments is not a true array, we need to make it one.
  // a handy trick for this is to use the slice function from array,
  // since it will take arguments, and return a real array.
  // we are storing it in a variable, because we will need to use it again.
  var slice =  Array.prototype.slice,
      // use slice to get an array of all additional arguments after the first two
      // that have been passed to this function.
      args = slice.call(arguments, 2);

  // we are returning a function mostly as a way to delay the execution.
  // as an aside, that this is possible in a mainstream language is a minor miracle
  // and a big part of why i love javascript.
  return function() {
    // since functions are objects in javascript, they can actually have methods.
    // this is one of the built in ones, that lets you execute a function in a different
    // context, meaning that the this variable inside the 
    // function will actually refer to the first argument we pass in.

    // the second argument we are jamming together the arguments from the first function
    // with the arguments passed in to this wrapper function, and passing it on to fn.
    // this lets us partially apply some arguments to fn when we call bind.
    return fn.apply(scope, args.concat(slice.call(arguments)));
  }
}
Run Code Online (Sandbox Code Playgroud)

JavaScript虽然精彩,却非常冗长.在定义绑定时不必要地重复var只会增加很多噪音.此外,没有必要像这样痛苦地构建一个真正的数组,切片将采用参数并给你一个真正的数组.特别是在我们使用它两次的情况下,我们实际上想要切掉前两个args.最后,当您申请并且您的第一个arg为null时,JavaScript将为您应用全局对象.没有必要明确地这样做.

IMO我的5行功能体从o'reillys 11行中踢出了废话,IMO它更具可读性.

  • @mjmitche:99%的时间他们想要有人可以进行翻转.js的专业知识通常意味着对大多数公司有良好的jquery知识,这足以完成大多数项目所需要的80-90%.就个人而言,我认为专门研究某事的人实际上应该对语言有更多熟悉,但在进行网络开发的程序员的宏大计划中,这似乎是少数意见.好消息是,如果你能在面试中描述如何写咖喱功能,那么大多数人都会走进去. (3认同)

Ale*_*yne 15

// define the curry() function
function curry(fn, scope) {

    // set the scope to window (the default global object) if no scope was passed in.
    scope = scope || window;

    // Convert arguments into a plain array, because it is sadly not one.
    // args will have all extra arguments in it, not including the first 2 (fn, scope)
    // The loop skips fn and scope by starting at the index 2 with i = 2
    var args = [];
    for (var i = 2, len = arguments.length; i < len; ++i) {
        args.push(arguments[i]);
    }

    // Create the new function to return
    return function() {

        // Convert any arguments passed to the this function into an array.
        // This time we want them all
        var args2 = [];
        for (var i = 0; i < arguments.length; i++) {
            args.push(arguments[i]);
        }

        // Here we combine any args originally passed to curry, with the args
        // passed directly to this function.
        //   curry(fn, scope, a, b)(c, d)
        // would set argstotal = [a, b, c, d]
        var argstotal = args.concat(args2);

        // execute the original function being curried in the context of "scope"
        // but with our combined array of arguments
        return fn.apply(scope, argstotal);
    };
}

// Create a function to be curried
function diffPoint(x1, y1, x2, y2) {
    return [Math.abs(x2 - x1), Math.abs(y2 - y1)];
}

// Create a curried version of the diffPoint() function
//   arg1: the function to curry
//   arg2: the scope (passing a falsy value causes the curry function to use window instead)
//   arg3: first argument of diffPoint() to bake in (x1)
//   arg4: second argument of diffPoint() to bake in (y1)
var diffOrigin = curry(diffPoint, null, 3.0, 4.0);

// Call the curried function
// Since the first 2 args where already filled in with the curry, we supply x2 and y2 only
var newPt = diffOrigin(6.42, 8.0);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,scope根本不使用该参数. scope设置this对象是什么.您正在使用的功能不会使用,this因此它没有实际效果.在fn.apply(scope, args)调用时设置范围,它既设置要运行的范围,也提供传入的参数.