考虑到文章过长,不便于阅读,这里分出第二篇,如有后续,每15个知识点分为一篇...

第一篇地址:( 译、持续更新 ) JavaScript 上分小技巧(一)

第三篇地址:( 译、持续更新 ) JavaScript 上分小技巧(三)

第四篇地址:( 译、持续更新 ) JavaScript 上分小技巧(四)

#30 - 将true的/false的值转换成boolean类型
你可以通过!!操作将为true/为false的值转换为boolean类型。

!!"" // false
!!0 // false
!!null // false
!!undefined // false
!!NaN // false

!!"hello" // true 字符串长度不为0时
!!1 // true
!!{} // true
!![] // true

### 2016-01-31 更新 ###

#29 - 使用缓存的记忆让递归函数加速运行
波非那切数列(Fibonacci sequence)想必大家都不陌生(针对学霸而言,在这之前本兽完全不知道这是个什么鬼,虽然经常会用到递归),我们可以在20秒内写出以下的函数:

var fibonacci = function(n){
    return n < 2 ? n : fibonacci(n-1) + fibonacci(n-2);
}

它确实是运行了,但是效率并不高。它做了大量的重复计算的工作,我们可以通过缓存先前计算结果的方法来加快速度。

var fibonacci = (function(){
    var cache = {
        0: 0,
        1: 1
    };
    return function(n){
        return n <= 1 ? cache[n] : (cache[n] = cache[n-1] + cache[n-2]);
    }
})()

同时,我们可以定义一个高阶函数,该高阶函数将接收一个函数作为参数并且该参数函数会返回一个已记忆的缓存版本。

var memoize = function(func){
    var cache = {};
    return function(){
        var key = Array.prototype.slice.call(arguments).toString();
        return key in cache ? cache[key] : (cache[key] = func.apply(this,arguments));
    }
}
fibonacci = memoize(fibonacci);

我们可以在很多情况下使用memoize()
GCD(最大公约数)

var gcd = memoize(function(a,b){
    var t;
    if (a < b) t=b, b=a, a=t;
    while(b != 0) t=b, b = a%b, a=t;
    return a;
})
gcd(27,183); //=> 3

阶乘计算

var factorial = memoize(function(n) {
    return (n <= 1) ? 1 : n * factorial(n-1);
})
factorial(5); //=> 120

#28 - 柯里化(局部套用)和局部应用
柯里化(局部套用)
柯里化将以下函数

f:X*Y_-R

转换为以下形式的函数:

f':X_>(Y->R)

我们仅调用f'配合第一个参数,来代替配合两个参数来调用f。返回的结果是一个我们配合第二个参数调用的函数并且返回结果值的函数。
因此,如果我们调用未柯里化的函数f:

f(3,5)

然后调用柯里化的函数f':

f(3)(5)

案例:
未柯里化的add()

function add(x, y) {
  return x + y;
}
add(3, 5);   // _> 8

柯里化的add()

function addC(x) {
  return function (y) {
    return x + y;
  }
}
addC(3)(5);   // _> 8

柯里化的运算法则:
柯里化取一个二元函数,返回一个包含一元函数的一元函数。
柯里化:

(X × Y → R) → (X → (Y → R))

javascript 代码:

function curry(f) {
  return function(x) {
    return function(y) {
      return f(x, y);
    }
  }
}

局部应用:
局部应用将以下函数

f:X*Y_-R

给定一个固定的值,传入一个参数,以此产生个新函数:

f':Y->R

f'和f不一样,但是他只需要填入第二个参数,这就是为什么f'比f的参数数量少一个。
案例:
绑定函数的第一个参数通过函数plus5进行与加5:

function plus5(y) {
  return 5 + y;
}
plus5(3);  // _> 8

局部应用的运算法则:
局部调用取一个二元函数和一个值,并且产生一个一元函数。
局部: ((X × Y → R) × X) → (Y → R)
javascript 代码:

function partApply(f, x) {
  return function(y) {
    return f(x, y);
  }
}

### 2016-01-30 更新 ###

#27 - 简短语句
Short-circuit evaluation指出,仅当第一个参数的论据不足以确定表达式的值的时候才执行第二个参数:当第一个参数的AND(&&)函数返回false,整体value也将是false;当第一个参数的OR(||)为true,则整体的值也是true。
以下是test情况和isTrue函数和isFalse函数:

var test = true;
var isTrue = function(){
  console.log('Test is true.');
};
var isFalse = function(){
  console.log('Test is false.');
};

使用AND(&&)逻辑:

// 正常语句.
if(test){
  isTrue();    // _> true
}
// 以上的功能使用 '&&' 完成
( test && isTrue() );  // _> true

使用OR(||)逻辑:

test = false;
if(!test){
  isFalse();    // _> false.
}
( test || isFalse());  // _> false.

逻辑OR(||)语句同时可以用来给函数的参数设置默认值:

function theSameOldFoo(name){
    name = name || 'Bar' ;
    console.log("My best friend's name is " + name);
}
theSameOldFoo();  // My best friend's name is Bar
theSameOldFoo('Bhaskar');  // My best friend's name is Bhaskar

逻辑AND(&&)语句同时可以用来避免使用undefined的属性的例外,案例:

var dog = {
  bark: function(){
     console.log('Woof Woof');
   }
};
// 调用 dog.bark();
dog.bark(); // Woof Woof.
//但是如果bog是undefined, dog.bark() 会抛出个错误 "Cannot read property 'bark' of undefined."
// 我们可以使用 && 来避免这种情况.
dog&&dog.bark();   // 这样的话,只有在bog存在的时候才会调用 dog.bark()

### 2016-01-28 更新 ###

#26 - 字符串列表的过滤和排序
你可能会有一个很大的字符串列表,你需要去对这个数组进行过滤和按字母排序。
在我们的例子中,我们将使用JavaScript来保存一系列的不同语言的关键字,但正如你所见,他们之间有重复,也没按字母顺序进行排序。所以这是一个完美的字符串列表(数组)来测试这个JavaScript小技巧。

var keywords = ['do', 'if', 'in', 'for', 'new', 'try', 'var', 'case', 'else', 'enum', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'delete', 'export', 'import', 'return', 'switch', 'typeof', 'default', 'extends', 'finally', 'continue', 'debugger', 'function', 'do', 'if', 'in', 'for', 'int', 'new', 'try', 'var', 'byte', 'case', 'char', 'else', 'enum', 'goto', 'long', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'final', 'float', 'short', 'super', 'throw', 'while', 'delete', 'double', 'export', 'import', 'native', 'public', 'return', 'static', 'switch', 'throws', 'typeof', 'boolean', 'default', 'extends', 'finally', 'package', 'private', 'abstract', 'continue', 'debugger', 'function', 'volatile', 'interface', 'protected', 'transient', 'implements', 'instanceof', 'synchronized', 'do', 'if', 'in', 'for', 'let', 'new', 'try', 'var', 'case', 'else', 'enum', 'eval', 'null', 'this', 'true', 'void', 'with', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'yield', 'delete', 'export', 'import', 'public', 'return', 'static', 'switch', 'typeof', 'default', 'extends', 'finally', 'package', 'private', 'continue', 'debugger', 'function', 'arguments', 'interface', 'protected', 'implements', 'instanceof', 'do', 'if', 'in', 'for', 'let', 'new', 'try', 'var', 'case', 'else', 'enum', 'eval', 'null', 'this', 'true', 'void', 'with', 'await', 'break', 'catch', 'class', 'const', 'false', 'super', 'throw', 'while', 'yield', 'delete', 'export', 'import', 'public', 'return', 'static', 'switch', 'typeof', 'default', 'extends', 'finally', 'package', 'private', 'continue', 'debugger', 'function', 'arguments', 'interface', 'protected', 'implements', 'instanceof'];

因为我们不打算改变原始列表,我们将使用一个名为filter的高阶函数,它会基于我们传递给它的函数进行过滤并且返回一个经过过滤的新数组。判断语句会将当前关键字的索引与新列表中的索引进行比较,如果索引能匹配上,则会将这项推到新的数组中。
最后,我们要使用排序功能以一个比较函数作为唯一的参数来对过滤后的列表进行排序,返回一个按字母顺序排序的列表。

var filteredAndSortedKeywords = keywords
  .filter(function (keyword, index) {
      return keywords.indexOf(keyword) === index;
    })
  .sort(function (a, b) {
      if (a < b) return -1;
      else if (a > b) return 1;
      return 0;
    });

ES6(ES 2015)使用arrow函数将会看上去简单些:

const filteredAndSortedKeywords = keywords
  .filter((keyword, index) => keywords.indexOf(keyword) === index)
  .sort((a, b) => {
      if (a < b) return -1;
      else if (a > b) return 1;
      return 0;
    });

这是进行过滤和排序后的关键字列表:

console.log(filteredAndSortedKeywords);
// ['abstract', 'arguments', 'await', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', 'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', 'with', 'yield']

### 2016-01-27 更新 ###

#25 - 使用立即执行函数表达式

被称为"Iffy"(IIFE-立即执行函数表达式)是一个在JavaScript中能够立即调用的匿名函数,并且还挺实用。

(function() {
// Do something
})()

用括号将匿名函数包裹起来,会将函数匿名函数转化成一个函数表达式或者变量表达式。因此,我们用一个未命名的函数表达式代替全局作用域下(或其他任何地方)的简单的匿名函数。

类似的,我们也可以为他创建一个名称,立即执行函数:

(someNamedFunction = function(msg) {
    console.log(msg || "Nothing for today !!")
}) (); // 输出 -> Nothing for today !!
someNamedFunction("Javascript rocks !!"); // 输出 -> Javascript rocks !!
someNamedFunction(); // 输出 -> Nothing for today !!

更多的信息,点击以下的链接 link1 link2
演示:jsPerf

### 2016-01-26 更新 ###

#24 - 使用 === 代替 ==
==(或者!=)做对比的时候会将进行对比的两者转换到同一类型再比较。===(或者!==)则不会,他会将进行对比的两者做类型对比和值对比,相对于 == ,=== 的对比会更加严谨。

[10] == 10     // true
[10] === 10    // false
"10" == 10     // true
"10" === 10    // false
[] == 0        // true
[] === 0       // false
"" == false    // true 但是 true == "a" 是false
"" === false   // false

#23 - 转换数值的更快的方法
将字符串转换为数字是非常常见的。最简单和最快的(jspref)方式来实现,就是使用+(加)算法。

var one = '1';
var numberOne = +one; // Number 1

你也可以使用-(减号)算法的转换类型并且变成负数值。

var one = '1';
var negativeNumberOne = -one; // Number -1

#22 - 清空一个数组
你定义一个数组,并希望清空它的内容。通常,你会这样做:

var list = [1, 2, 3, 4];
function empty() {
    //清空数组
    list = [];
}
empty();

但是还有一种更高性能的方法。
你可以使用这些代码:

var list = [1, 2, 3, 4];
function empty() {
    //清空数组
    list.length = 0;
}
empty();

· list = [] 将一个变量指定个引用到那个数组,而其他引用都不受影响。这意味着,对于先前数组的内容的引用仍然保留在内存中,从而导致内存泄漏。
· list.length = 0 删除数组内的所有东西,这不需要引用任何其他的东西
然而,如果你有一个copy的数组(A和copy-A),如果你使用list.length = 0 删除其内容,副本也会失去它的内容。

var foo = [1,2,3];
var bar = [1,2,3];
var foo2 = foo;
var bar2 = bar;
foo = [];
bar.length = 0;
console.log(foo, bar, foo2, bar2);
//[] [] [1, 2, 3] []

StackOverflow上的更多详情:difference-between-array-length-0-and-array

#21 - 对数组排序进行"洗牌"(随机排序)
这段代码在这里使用Fisher Yates洗牌算法给一个指定的数组进行洗牌(随机排序)。

function shuffle(arr) {
    var i,
        j,
        temp;
    for (i = arr.length - 1; i > 0; i--) {
        j = Math.floor(Math.random() * (i + 1));
        temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    return arr;
};

案例:

var a = [1, 2, 3, 4, 5, 6, 7, 8];
var b = shuffle(a);
console.log(b);
// [2, 7, 8, 6, 5, 3, 1, 4]

网友@幻天芒在评论中提供的随机技巧:

arr.sort(function(){return Math.random() - 0.5;});

实测可用,感谢分享!(性能方面相差3-4倍之间,shuffle执行比较快,根据个人喜欢来使用)

#20 - 返回对象的函数能够用于链式操作
当创建面向对象的JavaScript对象的function时,函数返回一个对象将能够让函数可链式的写在一起来执行。

function Person(name) {
  this.name = name;
  this.sayName = function() {
    console.log("Hello my name is: ", this.name);
    return this;
  };
  this.changeName = function(name) {
    this.name = name;
    return this;
  };
}
var person = new Person("John");
person.sayName().changeName("Timmy").sayName();
//Hello my name is:  John
//Hello my name is:  Timmy

#19 - 字符串安全连接
假设你有一些类型未知的变量,你想将它们连接起来。可以肯定的是,算法操作不会在级联时应用:

var one = 1;
var two = 2;
var three = '3';
var result = ''.concat(one, two, three); //"123"

这样的连接不正是你所期望的。相反,一些串联和相加可能会导致意想不到的结果:

var one = 1;
var two = 2;
var three = '3';
var result = one + two + three; //"33"  而不是 "123"

谈到性能,对join和concat进行比较,他们的执行速度是几乎一样的。你可以在MDN了解更多与concat相关的知识

#18 - 更快的四舍五入
今天的技巧是关于性能。见到过双波浪线"~~"操作符吗?它有时也被称为double NOT运算符。你可以更快的使用它来作为Math.floor()替代品。为什么呢?
单位移~将32位转换输入-(输入+1),因此双位移将输入转换为-(-(输入+1)),这是个趋于0的伟大的工具。对于输入的数字,它将模仿Math.ceil()取负值和Math.floor()取正值。如果执行失败,则返回0,这可能在用来代替Math.floor()失败时返回一个NaN的时候发挥作用。

// 单位移
console.log(~1337)    // -1338
// 双位移
console.log(~~47.11)  // -> 47
console.log(~~-12.88) // -> -12
console.log(~~1.9999) // -> 1
console.log(~~3)      // -> 3
//失败的情况
console.log(~~[]) // -> 0
console.log(~~NaN)  // -> 0
console.log(~~null) // -> 0
//大于32位整数则失败
console.log(~~(2147483647 + 1) === (2147483647 + 1)) // -> 0

虽然~~可能有更好的表现,为了可读性,请使用Math.floor()。

#17 - Node.js:让module在没被require的时候运行
在node里,你可以根据代是运行了require('./something.js')还是node something.js,来告诉你的程序去做两件不同的事情。如果你想与你的一个独立的模块进行交互,这是很有用的。

if (!module.parent) {
    // 运行 `node something.js`
    app.listen(8088, function() {
        console.log('app listening on port 8088');
    })
} else {
    // 使用 `require('/.something.js')`
    module.exports = app;
}

更多信息,请看the documentation for modules

#16 - 给回调函数传递参数
在默认情况下,你无法将参数传给回调函数,如下:

function callback() {
  console.log('Hi human');
}
document.getElementById('someelem').addEventListener('click', callback);

你可以采取JavaScript闭包的优点来给回调函数传参,案例如下:

function callback(a, b) {
  return function() {
    console.log('sum = ', (a+b));
  }
}
var x = 1, y = 2;
document.getElementById('someelem').addEventListener('click', callback(x, y));

什么是闭包呢?闭包是指一个针对独立的(自由)变量的函数。换句话说,闭包中定义的函数会记住它被创建的环境。了解更多请参阅MDN所以这种方式当被调用的时候,参数X/Y存在于回调函数的作用域内。
另一种方法是使用绑定方法。例如:

var alertText = function(text) {
  alert(text);
};
document.getElementById('someelem').addEventListener('click', alertText.bind(this, 'hello'));

两种方法在性能上有一些略微区别,详情参阅jsperf

### 2016-01-25 更新 ###

( 译、持续更新 ) JavaScript 上分小技巧(二)的更多相关文章

  1. ( 译、持续更新 ) JavaScript 上分小技巧(四)

    后续如有内容,本篇将会照常更新并排满15个知识点,以下是其他几篇译文的地址: 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第二篇地址:( 译.持续更新 ) JavaScr ...

  2. ( 译、持续更新 ) JavaScript 上分小技巧(三)

    最近家里杂事较多,自学时间实在少的可怜,所以都在空闲时间看看老外写的内容,学习之外顺便翻译分享~等学习的时间充足些再写写自己的一些学习内容和知识点分析(最近有在接触的:复习(C#,SQL).(学习)T ...

  3. ( 译、持续更新 ) JavaScript 上分小技巧(一)

    感谢好友破狼提供的这篇好文章,也感谢写这些知识点的作者们和将他们整理到一起的作者.这是github上的一篇文章,在这里本兽也就只做翻译,由于本兽英语水平和编程能力都不咋地,如有不好的地方也请多理解体谅 ...

  4. 文件上传小技巧/原生态【html篇】

    引语:大家都知道,html中上传文件就一个input,type=file就搞定了.但是,这个标签的样式,实在不值得提点什么,要改动他的样式,恐怕也是较难的.但是其实挺简单,今天就来说说上传文件小技巧吧 ...

  5. TypeScript和JavaScript的一些小技巧记录

    项目里使用到的技巧,记录一下,会持续更新. JS的技巧完全可以使用到TS上哦. JS 向下取整 Math.floor(4.5); 简写: var num = 4.5; ~~num; num <& ...

  6. Javascript字符串拼接小技巧

    在Javascript中经常会遇到字符串的问题,但是如果要拼接的字符串过长就比较麻烦了. 如果是在一行的,可读性差不说,如果要换行的,会直接报错. 在此介绍几种Javascript拼接字符串的技巧. ...

  7. 文件上传小技巧/后端处理【以php示例】

    引语:在上一篇文章中说到,在页面中可以用隐藏的方式让你的上传页面看起来漂亮.但是这对于性能来说,并没有什么卵用,那么在后台的处理中,难道就没有一些处理技巧么?所谓后台的技巧,应该要包括上传得快一点,上 ...

  8. JavaScript的一些小技巧(转)

    本文是一篇翻译文章,原文信息如下: 原文:45 Useful JavaScript Tips, Tricks and Best Practices 作者:Saad Mousliki JavaScrip ...

  9. sql多表更新使用别名(小技巧)

    update     A set     A.CityRegionID=B.ParentID,     A.CityName=(select RegionName from Common_Region ...

随机推荐

  1. 不要对外公开泛型List成员

    最近在阅读Framework Design Guidelines,本着现学现用的原则,于是就用FxCop工具对代码进行规范性检查时,发现了很多问题,其中包括命名以及一些设计上的规范. 其中,Do no ...

  2. C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 数据权限增强、范围权限增强

    并不是不想做B\S的管理工具,只是精力实在不够,由于用户权限管理组件是基础组件.所以C\S的也无妨,不会有几个人在乎Oracle,SQLServer是否不b\s的,注重的是功能性能,请大家不要纠结与是 ...

  3. Android之常用Git命令

    Android之常用Git命令 代码修改后提交步骤:git status:查看代码修改状态git diff:查看代码修改细节,也能看代码空格git add . :添加新加入的代码git commit ...

  4. NSURLSession的基本使用

    一.简单说明 在iOS9.0之后,以前使用的NSURLConnection过期,苹果推荐使用NSURLSession来替换NSURLConnection完成网路请求相关操作. NSURLSession ...

  5. A trip through the Graphics Pipeline 2011_07_Z/Stencil processing, 3 different ways

    In this installment, I’ll be talking about the (early) Z pipeline and how it interacts with rasteriz ...

  6. easyui+Spring MVC+hibernate = 乐途

    这个东西,玩的差不多了;不浪费口水了, 直接上图 发到blog 上让大家看看. 布局各方面有没有不足的地方 .请多多指教 http://item.taobao.com/item.htm?spm=686 ...

  7. hbase centOS生产环境配置笔记 (1 NameNode, 1 ResourceManager, 3 DataNode)

    本次是第一次在生产环境部署HBase,本文若有配置上的不妥之处还请高手指正. hadoop版本:hadoop-2.4.1 HBase版本:hbase-0.98.6.1-hadoop2 Zookeepe ...

  8. 本地替换文件读取MYSQL密码

    Mysql 的密码默认是存储在/data/mysql/下面的三个文件中:user.MYD,user.frm,user.MYI 先把这三个文件下载到本地,然后替换本地的这三个文件 使用net stop ...

  9. 一个商品练习的py

    #!/usr/bin/env python # coding=utf-8 # by 星空刺 qian = int(raw_input("请输入当前money:")) gongzi ...

  10. Windows-1252对Latin1编码有改变(并不完全兼容),而且Latin1缺失了好多西欧字符(法语,德语,西班牙语都有)

    主要是80到9F的编码被改掉了.从latin1的控制字符,变成了可以输出的可见字符. latin1编码: ISO-8859-1   x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA x ...