"30 seconds of code"中好玩的代码片段

2,411 阅读4分钟

最近做了github出现一个挺火的代码库"30 seconds of code",里面有不少好玩的代码片段,这里做一个分享,以下分享8个有趣的代码片段,有兴趣可以亲自点开看看

1、difference

Returns the difference between two arrays. Create a Set from b, then use Array.filter() on a to only keep values not contained in b.

const difference1 = (a, b) => { const s = new Set(b); return a.filter(x => !s.has(x)); };
// difference1([1,2,3], [1,2,4]) -> [3]

王二还想出了如下两种解决方法,也可以满足以上需求:

const difference2 = (a, b) => { return a.filter( _ => !b.some(($)=>(_===$))};

const difference3 = (a, b) => { return a.filter( _ => !b.includes(_))};

2、pick

Picks the key-value pairs corresponding to the given keys from an object. Use Array.reduce() to convert the filtered/picked keys back to a object with the corresponding key-value pair if the key exist in the obj.

const pick1 = (obj, arr) => arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {});
// pick1({ 'a': 1, 'b': '2', 'c': 3 }, ['a', 'c']) -> { 'a': 1, 'c': 3 }

如果不用reduce而使用一般的解决循环,也可以解决以上需求,例如王二如下给出的方法,不过用reduce一行就能搞定,当然是显得更优雅了。

const pick2 = (obj, arr) => {
    const res = {};
    arr.forEach(curr => (curr in obj && (res[curr] = obj[curr])));
    return res ;
};

3、zip

Creates an array of elements, grouped based on the position in the original arrays.

Use Math.max.apply() to get the longest array in the arguments. Creates an array with that length as return value and use Array.from() with a map-function to create an array of grouped elements. If lengths of the argument-arrays vary, undefined is used where no value could be found.

const zip1 = (...arrays) => {
  const maxLength = Math.max(...arrays.map(x => x.length));
  return Array.from({length: maxLength}).map((_, i) => {
   return Array.from({length: arrays.length}, (_, k) => arrays[k][i]);
  })
}
//zip1(['a', 'b'], [1, 2], [true, false]); -> [['a', 1, true], ['b', 2, false]]
//zip1(['a'], [1, 2], [true, false]); -> [['a', 1, true], [undefined, 2, false]]

以上需求一般的解决方法如下所示,可以用两层for循环搞定。但是很显然,上面的写法显得更优雅;

const zip2 = () => {
    var arr = Array.prototype.slice.call(arguments),
          maxLength = 0,
          out = [];
    arr.forEach(function(i){
        maxLength = Math.max(i.length,maxLength) ;
    })
    for(var x=0;x<maxLength;x++){
        var temp = [];
        for(var y=0;y<arr.length;y++){
            temp.push(arr[y][x]);
        }
        out.push(temp);
    }
    return out;
}

4、getBoundingClientRect()

dom元素使用getBoundingClientRect()可以获得其详细的位置。

5、getURLParameters

Returns an object containing the parameters of the current URL.

Use match() with an appropriate regular expression to get all key-value pairs, Array.reduce() to map and combine them into a single object. Pass location.search as the argument to apply to the current url.


const getURLParameters1 = () =>
  location.href.match(/([^?=&]+)(=([^&]*))/g).reduce(
    (a, v) => (a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1), a), {}
  );
// location.href = 'http://url.com/page?name=Adam&surname=Smith';
// getURLParameters() -> {name: 'Adam', surname: 'Smith'}

一般的解决思路如下,但是以上的方法用正则加reduce一行就能搞定;

const getURLParameters2 = () => {
    //取得查询字符串并去掉开头的问号
    var qs = (location.search.length > 0 ? location.search.substring(1) : ""),
    //保存数据的对象
    args = {},
    //取得每一项
    items = qs.length ? qs.split("&") : [],
    item = null,
    name = null, 
    value = null,
    //在 for 循环中使用
    i = 0,
    len = items.length;
    //逐个将每一项添加到 args 对象中
    for (i=0; i < len; i++){
        item = items[i].split("=");
        name = decodeURIComponent(item[0]);
        value = decodeURIComponent(item[1]);
        if (name.length) {
            args[name] = value;
        }
    }
    return args;
}

6、curry

Curries a function.

Use recursion. If the number of provided arguments (args) is sufficient, call the passed function f. Otherwise return a curried function f that expects the rest of the arguments. If you want to curry a function that accepts a variable number of arguments (a variadic function, e.g. Math.min()), you can optionally pass the number of arguments to the second parameter arity.

const curry = (fn, arity = fn.length, ...args) =>
  arity <= args.length
    ? fn(...args)
    : curry.bind(null, fn, arity, ...args);
// curry1(Math.pow)(2)(10) -> 1024
// curry1(Math.min, 3)(10)(50)(2) -> 2

一些王二一直弄不明白什么叫做柯里化,这个函数给王二好好上了一课;

7、pipe

Performs left-to-right function composition.

Use Array.reduce() with the spread operator (...) to perform left-to-right function composition. The first (leftmost) function can accept one or more arguments; the remaining functions must be unary.

const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
/*
const add5 = x => x + 5
const multiply = (x, y) => x * y
const multiplyAndAdd5 = pipeFunctions(multiply, add5)
multiplyAndAdd5(5, 2) -> 15
*/

王二第一次看到这个函数简直就是黑科技;

8、fibonacci

Generates an array, containing the Fibonacci sequence, up until the nth term.

Create an empty array of the specific length, initializing the first two values (0 and 1). Use Array.reduce() to add values into the array, using the sum of the last two values, except for the first two.

const fibonacci = n =>
  Array.from({ length: n}).map(v => 0).reduce((acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), []);
// fibonacci(5) -> [0,1,1,2,3]

一行函数搞定斐波那契数列。这里,王二觉得作者写的有些偏差,实际上,这里不需要map(v => 0),如下:

const fibonacci = n =>
  Array.from({ length: n}).reduce((acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), []);
// fibonacci(5) -> [0,1,1,2,3]

当然,还有其他的解决方案,如下:

const fibonacci = n =>
  Array(n).fill(0).reduce((acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), []);

一般的解决思路如下:

const fibonacci = n =>{
    var out = [];
    for(var i=0;i<n;i++){
        i > 1 ? out.push(out[i-1]+out[i-2]) : out.push(i);
    }
    return out ;
}

小结:无聊时看两段,每段理解起来不过30秒,实在是居家旅行必备的良品!赶紧戳进来看看

原文章发表于:王玉略的个人网站