javascript实用
JavaScript引擎是一个事件驱动的执行引擎,代码总是以单线程执行,而回调函数的执行需要等到下一个满足条件的事件出现后,才会被执行。
1. JavaScript不区分整数和浮点数,统一用Number表示。
NaN:表示Not a Number,当无法计算结果时用NaN表示。
Infinity:表示无限大,当数值超过JavaScript的Number所能表示的最大值时。
2. 比较运算符有==和===,不要使用==比较,应坚持使用===比较。
3. NaN和所有其他值都不相等,包括它自己:NaN === NaN // false
唯一能判断NaN的方法是通过isNaN()函数:isNaN(NaN) // ture
4. null表示一个“空”值,它和0以及空字符串””不同,0是一个数值,””表示长度为0的字符串,而null表示“空”。
undefined表示未定义。
大多数情况下,都应该用null,undefined仅仅在判断函数参数是否传递的情况下有用。
5. Javascript数组可以包括任意数据类型,元素之间用逗号(,)隔开。
除直接用[]创建数组外,还可以通过Array()函数创建数组,new Array(1, 2, 3)
通过length属性获取数组长度,arr.length
注意:直接给Array的length赋一个新的值会导致Array大小的变化。如果通过索引赋值时,索引超过了范围,同样会引起array大小的变化。
可通过join()方法把数组的每个元素用指定的字符串连接起来,然后返回连接后的字符串。
6. 变量名是大小写英文、数字、$和_的组合,且不能用数字开头。
同一个变量可以反复赋值,而且可以是不同类型的变量,但是注意只能用var申明一次。
7. 对象是一种无序的集合数据类型,由若干键值对组成。用{...}表示一个对象,键值对以xxx:xxx形式申明,用逗号隔开。
键是对象的属性,访问属性通过点号(.)访问,所有属性都是字符串,值可以是任意类型。
如果属性名包含特殊字符,必须用’’括起来,且不可用点号访问,必须用[]访问。
删除属性用delete。
检测对象是否有某一属性,用in操作符。不过要小心,如果in判断一个属性存在,这个属性不一定是对象的,可能是该对象集成得到的。
要判断一个属性是否是对象自身拥有的,而不是集成得到的,可以用hasOwnProperty()方法。
8. for循环的一个变体是for...in循环,可以把一个对象的属性循环出来:
var o = { name: ‘Jack‘, age: 20, city: ‘Beijing‘ }; for (var key in o) { if (o.hasOwnProperty(key)) { console.log(key); // ‘name‘, ‘age‘, ‘city‘ } }
9. Map是一组键值对的结构,具有极快的查找速度,map的键可以是任意数据类型。初始化map需要一个二维数组,或者直接初始化一个空的。
var m = new Map([[‘Wang’, 96], [‘Li’, 94’], [‘Yu’, 80]]); m.get(‘wang’) m.set(‘wang’, 80) m.delete(‘wang’)
10. set是一组key的集合,不存储value,key不能重复(重复key自动过滤)
创建一个set,需要提供一个array最为输入,或者直接创建一个空的set。
11. Array、map和set都属于iterable类型,通过for... of循环遍历,只循环集合本身的元素。
Iterable内置forEach方法,它接收一个函数,每次迭代就自动回调该函数。
var a = [‘a‘, ‘b‘, ‘c‘] a.forEach(function (value, index, array){ console.log(value + ‘, index= ‘ + index + ‘, array: ‘ + array) }
数组的回调函数,参数依次是元素值,索引和对象本身。
Set和数组类似,但set没有索引,因此回调函数的前两个参数都是元素本身。
Map的回调函数参数依次为value,key和map本身。
12. 函数如果没有return语句,函数执行完毕后返回结果undefined。
13. JavaScript允许传入任意个参数而不影响调用,参数的使用由函数内部确定。
abs() // 返回NaN
此时abs(x)函数的参数x将收到undefined,计算结果为NaN。
要避免收到undefined,可以对参数进行检查:
function abs(x) { if (typeof x !== ‘number‘) { throw ‘Not a number‘; } if (x >= 0) { return x; } else { return -x; } }
14. 关键字arguments只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。Arguments类似Array但它不是一个Array。Arguments常用语判断传入参数的个数arguments.length。
15. ES6引入rest参数,表征剩余参数:function foo(a, b, ...rest)
Rest参数只能写在最后,前面用...标识,多余的参数以数组形式交给变量rest。如果传入的参数连正常定义的参数都没有填满,rest参数会接收一个空数组(不是undefined)。
16. 函数定义时会扫描整个函数体的语句,把所有申明的变量“提升”到函数的顶部,但不会提升变量的赋值(未定义的变量默认定义为undefined)。
function foo(){ var x = y console.log(x) // undefined var y = {name: "wang", id: "1"} console.log(y) // {name: ‘wang’, id: ‘1’} } foo()
据此,应严格遵守“在函数内部首先申明所有变量”规则,通过var首先申明变量。
17. 为了减少命名冲突,应该把自己的所有变量和函数全部绑定到一个全局变量中,从而减少与全局变量window等的冲突,如jQuery、underscore都是这样做的。
18. 作用域:JavaScript的变量作用域实际上是函数内部,在for循环等语句块中无法定义局部作用域的变量。ES6引入关键字let来代替var申明一个块级作用域变量。
for (let i=0; i < 100; i++){sum +=i}
19. ES6引入关键字const定义常量,const和let都是块级作用域,常量一般用大写字母。
20. 在一个对象中绑定的函数是对象的方法。在方法内部,this是一个特殊变量,始终指向当前对象,且只在对象的顶层函数中指向对象,否则执行全局对象window或undefined,报TypeError错误。
21. 字符串操作函数
Split:"house".split(‘‘) // [‘h’, ‘o’, ‘u’, ‘s’, ‘e’]
22. 高阶函数:函数的参数中包含函数。
23. map/reduce MapReduce: Simplified Data Processing on Large Clusters
Map和reduce都是array的方法,参数都是函数。
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
function pow(x){ return x * x } function sum(x, y){ return x + y } var results = [1, 2, 3, 4].map(pow) // [1, 4, 9, 16] var resultsRes = [1, 2, 3, 4].reduce(sum) // 10
24. 闭包:函数返回函数。
注意:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
25. 箭头函数相当于匿名函数,并且简化了函数定义:
x => x*x
x => {return x * x }
返回对象: x => ({foo: x})
箭头函数的this总是指向词法作用域,也就是外层调用者obj。
26. 在JavaScript中,所有代码都是单线程执行的。若要异步执行可以用Promise对象,Promise可以在异步执行流程中,把执行代码和处理结果代码清晰分离。
new Promise(function (reslove, reject){ console.log("this is promise program") var timeout = Math.random()*2 console.log(‘set timeout to : ‘ + timeout + ‘ second‘) setTimeout(function(){ if (timeout < 1){ console.log(‘call resolve()...‘) reslove(‘200 OK‘) } else { console.log(‘call reject()...‘) reject("timeout") } }, 1000) }).then(function(a){ console.log(a) // resolve() return: 200 OK }).catch(function(b){ console.log(b) // reject() return: timeout } job1.then(job2).then(job3).catch(handleError);
Job1、job2和job3串行执行任务。
并行执行任务用Promise.all():
var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, ‘P1‘); }); var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, ‘P2‘); });// 同时执行p1和p2,并在它们都完成后执行then: Promise.all([p1, p2]).then(function (results) { console.log(results); // 获得一个Array: [‘P1‘, ‘P2‘] });
同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可,用Promise.race()实现:(执行相应时间短的,其他丢弃)
var p1 = new Promise(function (resolve, reject) { setTimeout(resolve, 500, ‘P1‘); }); var p2 = new Promise(function (resolve, reject) { setTimeout(resolve, 600, ‘P2‘); }); Promise.race([p1, p2]).then(function (result) { console.log(result); // ‘P1‘ });
27. JavaScript有一个标准的Error对象表示错误,还有从Error派生的TypeError、ReferenceError等错误对象。我们在处理错误时,可以通过catch(e)捕获的变量e访问错误对象。
28. 涉及到异步代码,无法在调用时捕获错误,原因就是在捕获的当时,回调函数并未执行。类似的,当我们处理一个事件时,在绑定事件的代码处,无法捕获事件处理函数的错误。应在错误发生的函数中捕获错误。哪里出错哪里才能try-catch捕获。
29. Underscore提供了一套完善的函数式编程接口,把自身绑定到唯一的全局变量_上。
参考: