后续如有内容,本篇将会照常更新并排满15个知识点,以下是其他几篇译文的地址:

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

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

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

#59 - ES6,var vs let

var关键字定义的变量根据定义的环境用于function内,function外或者全局;而let定义的变量只用于"块"范围。

function varvslet() {
console.log(i); // i is undefined 由于变量提升
// console.log(j); // ReferenceError: j is not defined for( var i = 0; i < 3; i++ ) {
console.log(i); // 0, 1, 2
}; console.log(i); //
// console.log(j); // ReferenceError: j is not defined for( let j = 0; j < 3; j++ ) {
console.log(j);
}; console.log(i); //
// console.log(j); // ReferenceError: j is not defined
}

从上面代码可以看出,let不会得到提升,且仅用于该变量使用的块范围。

let存在自己封闭的块范围,并且在循环场景中会确保在上一次循环迭代结束重新分配它的值:

for (var i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i); // 由于异步,输出 5, 5, 5, 5, 5
}, 100);
} for (let i = 0; i < 5; ++i) {
setTimeout(function () {
console.log(i); // 输出 0, 1, 2, 3, 4
}, 100);
}

参考资料:

Let keyword vs var keyword

For and against let

Explanation of let and block scoping with for loops

#58 - 跳出/继续执行循环语句

对于for循环,我们通常用break来跳出循环:

const a = [0, 1, 2, 3, 4];
for (var i = 0; i < a.length; i++) {
if (a[i] === 2) {
break; // stop the loop
}
console.log(a[i]);
}
//> 0, 1

在forEach中,就不能用break来跳出循环了,与之功能最相近的是return了:

[0, 1, 2, 3, 4].forEach(function(val, i) {
if (val === 2) {
// 我们该怎么跳出循环呢?
return true;
}
console.log(val);
});
//> 0, 1, 3, 4

.some是Array原型上的一个方法,用于检测该数组中是否存在满足提供的规则的元素,当检测到元素满足条件并且返回true,则会停止继续执行。.some MDN详细资料

const isBiggerThan10 = numb => numb > 10;

[2, 5, 8, 1, 4].some(isBiggerThan10);  // false
[12, 5, 8, 1, 4].some(isBiggerThan10); // true [0, 1, 2, 3, 4].some(function(val, i) {
if (val === 2) {
return true;
}
console.log(val); // your code
});
//> 0, 1

使用.some,实现了和forEach相似的功能,并且在满足给定条件时会跳出循环。

使用.some,我们必须返回相反的值。当return的是false,循环会继续执行。

const isTwoPresent = [0, 1, 2, 3, 4].some(function(val, i) {
if (val === 2) {
return true; // break
}
console.log(val);
});
console.log(isTwoPresent);
//> true // 当return的是true时,console.log(val)会输出:0,1;当return的是false时,console.log(val)会输出0,1,3,4

#57 - JavaScript中的逗号运算符

众所周知,逗号运算符可以作为分隔符抑或同时执行多个变量声明,如:

for(var i=0, j=0; i<5; i++, j++, j++){
console.log("i:"+i+", j:"+j);
}
// 输出:
i:0, j:0
i:1, j:2
i:2, j:4
i:3, j:6
i:4, j:8

然而当放在表达式中,他会从左到右的评估每一个表达式,并且返回最右表达式的结果。

function a(){console.log('a'); return 'a';}
function b(){console.log('b'); return 'b';}
function c(){console.log('c'); return 'c';} var x = (a(), b(), c());
console.log(x);
// 输出:
"a"
"b"
"c" "c"

注意:逗号运算符在JavaScript中优先级是最低的,所以,当没有大括号的时候,表达式会变成:var (x = a()), b(), c();

#56 - JavaScript 拷贝到剪切板

现在有个需求,我们想要将字符串拷贝到剪切板中以供粘贴,用js怎么操作呢?

其实实现起来很简单,我们需要一个input来作为拷贝内容的载体,然后选择拷贝内容,执行execCommand命令即可。execCommand('copy')命令会将实际选中的值拷贝到剪切板,当然,也可以是cut,paste等命令。

<input type="text" class="copy" value="hello world" />
<input type="text" class="paste" />
document.querySelector('.do-copy').addEventListener('click',function(e){
document.querySelector('.copy').select();
document.execCommand('copy');
},!1)

参考资料:execCommand MDN

然而发现各种测paste命令,好像存在问题,stackoverflow上的解答也不尽人意...(没能满意的跑顺畅)

### 2016-10-02 更新 ###

# 55 - 让数组进行多次循环

有些时候,我们需要对一个数组进行多次循环。以下代码展示了如何进行一个数组的循环。

var aList = ['A','B','C','D','E'];

function make_looper( arr ){

    arr.loop_idx = 0;

    // 返回当前循环到的元素
arr.current = function(){ if( this.loop_idx < 0 ){// 第一次验证
this.loop_idx = this.length - 1;// 更新循环索引
} if( this.loop_idx >= this.length ){// 第二次验证
this.loop_idx = 0;// 更新循环索引
} return arr[ this.loop_idx ];//return item
}; // 对循环索引进行一次加操作,并且返回当前元素
arr.next = function(){
this.loop_idx++;
return this.current();
};
// 对循环索引进行一次减操作,并且返回当前元素
arr.prev = function(){
this.loop_idx--;
return this.current();
};
} make_looper( aList); aList.current();// -> A
aList.next();// -> B
aList.next();// -> C
aList.next();// -> D
aList.next();// -> E
aList.next();// -> A
aList.pop() ;// -> E
aList.prev();// -> D
aList.prev();// -> C
aList.prev();// -> B
aList.prev();// -> A
aList.prev();// -> D

使用%操作符便更好了:

var aList = ['A','B','C','D','E'];

function make_looper( arr ){

    arr.loop_idx = 0;

    // 返回当前循环到的元素
arr.current = function(){
this.loop_idx = ( this.loop_idx ) % this.length;// 没有验证 !!
return arr[ this.loop_idx ];
}; // 对循环索引进行一次加操作,并且返回当前元素
arr.next = function(){
this.loop_idx++;
return this.current();
}; // 对循环索引进行一次减操作,并且返回当前元素
arr.prev = function(){
this.loop_idx += this.length - 1;
return this.current();
};
} make_looper( aList); aList.current();// -> A
aList.next();// -> B
aList.next();// -> C
aList.next();// -> D
aList.next();// -> E
aList.next();// -> A
aList.pop() ;// -> E
aList.prev();// -> D
aList.prev();// -> C
aList.prev();// -> B
aList.prev();// -> A
aList.prev();// -> D

# 53 - 获取文件扩展名

如何获取文件扩展名?

var file1 = "50.xsl";
var file2 = "30.doc";
getFileExtension(file1); //return xsl
getFileExtension(file2); //return doc function getFileExtension(filename) {
/*TODO*/
}

解决方案一:

function getFileExtension1(filename) {
return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename)[0] : undefined;
}

解决方案二:

function getFileExtension2(filename) {
return filename.split('.').pop();
}

然而这两个解决方案并不能满足一些特殊情况,下面是一个更好的解决方案。

解决方案三(使用slice和lastIndexOf):

function getFileExtension3(filename) {
return filename.slice((filename.lastIndexOf(".") - 1 >>> 0) + 2);
} console.log(getFileExtension3('')); // ''
console.log(getFileExtension3('filename')); // ''
console.log(getFileExtension3('filename.txt')); // 'txt'
console.log(getFileExtension3('.hiddenfile')); // ''
console.log(getFileExtension3('filename.with.many.dots.ext')); // 'ext'

日常解释以上代码:

. String.lastIndexOf() 方法返回指定值的最后一个符合条件的值(在此案例中是"."),如果没有值则返回-1。

. "filename"和".hiddenfile"执行"lastIndexOf"方法后返回的值分别是0和-1。无符号右位移操作符 将-1转化为4294967295,-2转化为4294967294,这个小技巧用以确保在一些特殊情况下文件名不会被改变(当取"."的lastIndexOf为0或者-1时,截取的便是整个文件名,无符号右位移2位,这时则变成了Integer的最大值,免去了"没有扩展名、只有扩展名"这两个条件的判断)。

. String.prototype.slice() 根据上面的计算方式得出的index来提取文件扩展名。如果返回的index值大与文件名的长度,则返回""。

解决方案四(使用正则,好友 @chengby 提供):

function getExt(file){
return file.match(/\S+\.+(\S*)/)?file.match(/\S+\.+(\S*)/)[1]:"";
}

对比:

解决方案一
''                                                 undefined
'filename'                                     undefined
'filename.txt'                                'txt'
'.hiddenfile'                                  'hiddenfile'
'filename.with.many.dots.ext'        'ext'
解决方案二
''                                                ''
'filename'                                    'filename'
'filename.txt'                               'txt'
'.hiddenfile'                                 'hiddenfile'
'filename.with.many.dots.ext'        'ext'
解决方案三
''                                                 ''
'filename'                                     ''
'filename.txt'                                'txt'
'.hiddenfile'                                  ''
'filename.with.many.dots.ext'        'ext'

解决方案四
''                                                 ''
'filename'                                     ''
'filename.txt'                                'txt'
'.hiddenfile'                                  ''
'filename.with.many.dots.ext'        'ext'

### 2016-06-02 更新 ###

# 52 - "new"操作的返回值(构造函数的返回值)

在一些情况下,我们会使用"new"来为对象指定一个新的实例。本章将展示一些使用"new" 生成实例背后发生的事情。

"new" 在JavaScript中是一个操作符,在合理的情况下会返回一个对象的实例。这意味着我们需要一个构造函数:

function Thing() {
this.one = 1;
this.two = 2;
} var myThing = new Thing(); myThing.one //
myThing.two //

注意:this 指向的是通过"new"所创建的新对象。如过直接调用Thing(),而不是通过new 操作,则不会创建对象,这时候的this 指向的是全局对象,也就是window 。

1.这时候你会突然发现多了2个全局变量,one和two。

2.myThing 现在是undefined,因为Thing()没有返回任何值。

现在,我们得到下一个例子,看着不怎么可靠的例子。这里我们对构造函数加了些料:

function Thing() {
this.one = 1;
this.two = 2; return 5;
} var myThing = new Thing();

现在myThing等于什么呢?5?一个对象?

结果是:

myThing.one //
myThing.two //

有趣的是,我们并没有看到理应从构造函数中返回的数值5 。这很奇怪,不是么?函数发生了什么?5在哪?那么再试试其他的看看。

我们return一个非原始类型看看,返回一个对象:

function Thing() {
this.one = 1;
this.two = 2; return {
three: 3,
four: 4
};
} var myThing = new Thing();

我们console下,看看是什么样的结果:

console.log(myThing);
/**************************************************
** Object {three: 3, four: 4}
** this.one 和 this.two 竟然不见了,发生了什么?
***************************************************/

这里正是我们需要学习的:当你结合"new"关键字调用一个函数的时候,你可以使用this 关键字设置属性(你可能已经知道了)。如果使用new关键字操作存在返回原始值的函数,将不会得到你所期望的值,而是返回这个函数所构造的实例(你所设置的属性,如 this.one = 1 ; )

然而,当返回值是非原始类型的时候,如object、array,或者function,那么将覆盖这个实例,并且返回这个非原始类型的值,完全将你对这个this上的属性指定给覆盖了。

### 2016-04-14 更新 ###

#51 - 轻松的监听DOM事件

大部分人依旧这么做:

· element.addEventListener('type', obj.method.bind(obj))
· element.addEventListener('type', function (event) {})
· element.addEventListener('type', (event) => {})

上面的例子都可以创建一个新的匿名事件处理,当这些事件不再被需要的时候,不会被删除。当不再需要的事件被用户意外操作或者事件冒泡而触发,则可能导致性能问题或意外的逻辑bug。

安全的事件处理模式应当如下:

参考使用

const handler = function () {
console.log("Tada!")
}
element.addEventListener("click", handler)
// 之后
element.removeEventListener("click", handler)

对函数命名并且移除事件

element.addEventListener('click', function click(e) {
if (someCondition) {
return e.currentTarget.removeEventListener('click', click);
}
});

更好的方法:

function handleEvent (eventName, {onElement, withCallback, useCapture = false} = {}, thisArg) {
const element = onElement || document.documentElement function handler (event) {
if (typeof withCallback === 'function') {
withCallback.call(thisArg, event)
}
} handler.destroy = function () {
return element.removeEventListener(eventName, handler, useCapture)
} element.addEventListener(eventName, handler, useCapture)
return handler
} // 需要用到的时候
const handleClick = handleEvent('click', {
onElement: element,
withCallback: (event) => {
console.log('Tada!')
}
}) // 需要移除的时候
handleClick.destroy()

### 2016-03-21 更新 ###

#50 - 实用的控制台打印技巧

在执行代码的时候,你可以想要知道函数中某个变量值是否发生改变抑或查看代码执行是否有效,很多人习惯用"alert"来在适当的地方弹出显示,然而这是不方便的,一方面alert能显示的结果有限(如打印object时将会是[object Object]),另一方面它阻碍了代码的继续执行。

我们应该更需要去熟悉使用浏览器的开发工具--Console(用于显示数据)和Sources(用于断点跟踪)。这里我们不多做介绍,只给出相应的图片展示吧:

console.log(value);

使用断点:

更多学习应用控制台的文章:Debugging JavaScript(Chrome) 、 Set a conditional breakpoint(FireFox) 、 Debugger(Edge) 、Firebug控制台详解

#49 - JS中最简单的方式获取时间戳

我们经常需要获取时间戳进行计算,有好几种方式来获取时间戳,目前最简单也是最快的方法是:

const timestamp = Date.now();

或者

const timestamp = new Date().getTime();

获取具体时间 yyyy-mm-dd 的时间戳,我们可以通过给Date构造函数传入一个参数,例如:

const timestamp = new Date('2012-06-08').getTime()

也可以在声明日期对象时添加一个+符号,如下所示:

const timestamp = +new Date()

或者获取指定日期的时间戳

const timestamp = +new Date('2012-06-08')

引擎中调用了Date对象valueOf方法,返回一元运算符"+"配合返回的值调用toNumber()。更多详细说明请查看以下链接:

Date.prototype.valueOf 
一元运算符"+" 
toNumber()

#48 - 内置函数reduce的用法
正如文档所写,reduce()方法应用一个函数以针对数组的值(从左到右)减至最后一个值。
reduce()
reduce()方法接收两个参数(M:mandatory,O:options):
 (M)一个回调函数,用于处理与先前的计算结果和下一个元素。
 (O)被作为回调函数的第一个调用的参数的初始值。
所以,我们来看看普通用法,后面再来一个更先进的。
常见的用法(积累,连接)
假如我们在购物,并且购物车足够满,让我们计算价格总和:

// 现在的价格
var items = [{price: 10}, {price: 120}, {price: 1000}];
// reducer函数
var reducer = function add(sumSoFar, nextPrice) { return sumSoFar + nextPrice.price; };
// 处理...
var total = items.reduce(reducer, 0);
console.log(total); //

函数的可选参数在一般情况下是0,它可以是个对象,也可以是个数组。
现在,我们获得一张20元的代金券:

var total = items.reduce(reducer,-20);
console.log(total); //

高端用法(组合)
落后的思想是将reducers分别写成单独的功能,并最终计算出一个新的reducers的功能。
为了说明这一点,让我们创建一个对象与一些能够计算不同货币美元的总价格的reducers功能。

var reducers = {
totalInDollar: function(state, item) {
state.dollars += item.price;
return state;
},
totalInEuros : function(state, item) {
state.euros += item.price * 0.897424392;
return state;
},
totalInYen : function(state, item) {
state.yens += item.price * 113.852;
return state;
},
totalInPounds : function(state, item) {
state.pounds += item.price * 0.692688671;
return state;
}
// 更多...
};

然后,我们创建一个新的功能:
 · 负责应用reduce的各部分功能。
 · 将返回一个新的回调函数。

var combineTotalPriceReducers = function(reducers) {
return function(state, item) {
return Object.keys(reducers).reduce(
function(nextState, key) {
reducers[key](state, item);
return state;
},
{}
);
}
};

现在,让我们看看怎么使用这个:

var bigTotalPriceReducer = combineTotalPriceReducers(reducers);
var initialState = {dollars: 0, euros:0, yens: 0, pounds: 0};
var totals = items.reduce(bigTotalPriceReducer, initialState);
console.log(totals);
/*
Object {dollars: 1130, euros: 1015.11531904, yens: 127524.24, pounds: 785.81131152}
*/

我希望这个方法能够在你所需要的时候给你提供一个reduce使用的思路。
#47 - 基本声明
下面是javascript中声明变量的不同方式。console.log能够很好的解释这里将发生什么。

var y, x = y = 1 //== var x; var y; x = y = 1
console.log('_> 1:', `x = ${x}, y = ${y}`)
// 将会打印
//_> 1: x = 1, y = 1

首先,我们设置两个变量,在这里没更多的操作。

;(() => {
var x = y = 2 // == var x; y = 2;
console.log('2.0:', `x = ${x}, y = ${y}`)
})()
console.log('_> 2.1:', `x = ${x}, y = ${y}`)
// 将会打印
//2.0: x = 2, y = 2
//_> 2.1: x = 1, y = 2

正如你所见的,这里的代码只改变了全局的y,因为我们没有在闭包中声明变量。

;(() => {
var x, y = 3 // == var x; var y = 3;
console.log('3.0:', `x = ${x}, y = ${y}`)
})()
console.log('_> 3.1:', `x = ${x}, y = ${y}`)
// 将会打印
//3.0: x = undefined, y = 3
//_> 3.1: x = 1, y = 2

现在我们通过var来声明变量。这意味着他们只存在封闭的语境中。

;(() => {
var y, x = y = 4 // == var x; var y; x = y = 4
console.log('4.0:', `x = ${x}, y = ${y}`)
})()
console.log('_> 4.1:', `x = ${x}, y = ${y}`)
// 将会打印
//4.0: x = 4, y = 4
//_> 4.1: x = 1, y = 2

这两个变量都通过var声明并且只会给定了值。因为local>global,所以x和y在本地封闭语境中,意味着全局的x和y没做改变。

x = 5 // x = 5
console.log('_> 5:', `x = ${x}, y = ${y}`)
// 将会打印
//_> 5: x = 5, y = 2

这最后一行是明确的。
更多的变量相关信息:MDN
#46 - js纯粹的检测文档加载完毕
使用javascript的 readyState 以跨浏览器的方式来检测文档是否加载。

if (document.readyState === 'complete') {
// 页面已经完全加载
}

你能够检查文档是否加载...

let stateCheck = setInterval(() => {
if (document.readyState === 'complete') {
clearInterval(stateCheck);
// document ready
}
}, 100);

或者使用onreadystatechange...

document.onreadystatechange = () => {
if (document.readyState === 'complete') {
// document ready
}
};

使用document.readyState === 'interactive'检测DOM是否ready。
          ### 2016-02-18 更新 ###

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

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

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

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

    考虑到文章过长,不便于阅读,这里分出第二篇,如有后续,每15个知识点分为一篇... 第一篇地址:( 译.持续更新 ) JavaScript 上分小技巧(一) 第三篇地址:( 译.持续更新 ) Java ...

  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. 19个JavaScript简化编码小技巧

    这篇文章适合任何一位基于JavaScript开发的开发者.我写这篇文章主要涉及JavaScript中一些简写的代码,帮助大家更好理解一些JavaScript的基础.希望这些代码能从不同的角度帮助你更好 ...

  7. Javascript字符串拼接小技巧

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

  8. 一些有意思的面试题(持续更新) .C语言编程技巧札记

    一些有意思的面试题(持续更新) http://blog.csdn.net/wangyuling1234567890/article/details/38565239 C语言编程技巧札记 http:// ...

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

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

随机推荐

  1. 我和Lua并非一见钟情,我们期待着日久生情(相遇篇)

    Lua作为一款轻量级的脚本语言,由标准C编写而成,可被C/C++调用,也可调用C/C++的函数. 在目前的脚本引擎中,Lua的速度是最快的... Lua可直接在EditPlus文本处理器上开发,只需搭 ...

  2. web性能优化——简介

    简介 性能优化的第一准则:加缓存.几乎绝大部分优化都围绕这个来进行的.让用户最快的看到结果. 性能优化的第二准则:最小原则.绝不提供多余的信息.比如,静态资源(图片.css.js)压缩,图片的滚动加载 ...

  3. 备忘:powerbroker运行一个命令

    pbrun su<space>-<space><taget user name> example: pbrun su - pmsdev

  4. md5加密篇(一)

    /// <summary> /// 获取文件的md5摘要 /// </summary> /// <param name="sFile">文件流& ...

  5. 深入浅出ASP.NET MVC5系列之一

    前言 为避免看官乏味,本系列博客限定在较新的.Net framework 4.5.1,Asp.net MVC5,IIS 7.X集成模式. 对于微软应用层的技术.我向来不舍得花太多时间学习.但又由于公司 ...

  6. px和em和rem的区别

    一.px特点: 1. IE无法调整那些使用px作为单位的字体大小: 2. 国外的大部分网站能够调整的原因在于其使用了em或rem作为字体单位: 3. Firefox能够调整px和em,rem,但是96 ...

  7. Redis集群(一):基本概念

    一.使用版本:3.0.0.0 二.基本概念:  号至 11000 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了. 异步复制(虽然是异步复制,但是执行写命令和复制命令到从节点几乎是 ...

  8. javascript 方法实例

    输出对象的属性名称与值 : boj(o){ for(var p in o){ console.log(p + ":" + o[p] + "\n"); } } 构 ...

  9. 同 一个页面,不同请求路径,如何根据实际场景写JS

    场景:使用同一个“添加群成员”的页面来操作 建群页面:建群成功后,返回查看群成员页面.在建群过程中直接添加群成员并返回一个群名称的参数. 添加群成员页面:在巳有群内添加群成员,添加成功后,返回查看群成 ...

  10. hdu2665 && poj2104划分树

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 47066   Accepted: 15743 Ca ...