JavaScript笔记
语法
编译器自动在每个语句的结尾添加 ;
数据类型
JS不区分整数与浮点数,统一用Number
表示,NAN
表示Not a Number
, Infinity
表示无限大,表示超过JavaScript
的表示范围,null
表示一个“空”的值,它和0
以及空字符串''
不同,0
是一个数值,''
表示长度为0的字符串,而null
表示“空”,undefined
表示值未定义。事实证明,这并没有什么卵用,区分两者的意义不大,大多数情况用null
,undefined
仅仅在判断函数参数是否传递的情况下有用。
变量名是大小写英文、数字、$
和_
的组合,且不能用数字开头,变量名前不加var代表是全局变量(不建议使用)
启用strict模式的方法是在JavaScript代码的第一行写上:'use strict';
字符串
模板字符串
如果有很多变量需要连接,用+号就比较麻烦。ES6新增了一种模板字符串,表示方法和上面的多行字符串一样,但是它会自动替换字符串中的变量:
var name = '小明';
var age = 20;
var message = `你好, ${name}, 你今年${age}岁了!`;
alert(message);
需要特别注意的是,字符串是不可变的,
-
toUpperCase()
把一个字符串全部变为大写 -
toLowerCase()
把一个字符串全部变为小写 -
indexOf()
会搜索指定字符串出现的位置 -
substring(begin,end)
返回指定索引区间的子串
var s = 'hello, world';
s.indexOf('world'); // 返回7
s.indexOf('World'); // 没有找到指定的子串,返回-1
var s = 'hello, world'
s.substring(0, 5); // 从索引0开始到5(不包括5),返回'hello'
s.substring(7); // 从索引7开始到结束,返回'world'
数组
JavaScript的Array
可以包含任意数据类型
另一种创建数组的方法是通过Array()
函数实现:(不建议使用)new Array(1, 2, 3); // 创建了数组[1, 2, 3]
要取得Array
的长度,直接访问length
属性
slice(begin,end)
就是对应String
的substring()
版本,它截取Array
的部分元素,然后返回一个新的Array
与String
类似,Array
也可以通过indexOf()
来搜索一个指定的元素的位置push()
向Array
的末尾添加若干元素,pop()
则把Array
的最后一个元素删除掉如果要往
Array
的头部添加若干元素,使用unshift()
方法,shift()
方法则把Array
的第一个元素删掉splice()
方法是修改Array的“万能方法”,它可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素
var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];
// 从索引2开始删除3个元素,然后再添加两个元素:
arr.splice(2, 3, 'Google', 'Facebook'); // 返回删除的元素 ['Yahoo', 'AOL', 'Excite']
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
// 只删除,不添加:
arr.splice(2, 2); // ['Google', 'Facebook']
arr; // ['Microsoft', 'Apple', 'Oracle']
// 只添加,不删除:
arr.splice(2, 0, 'Google', 'Facebook'); // 返回[],因为没有删除任何元素
arr; // ['Microsoft', 'Apple', 'Google', 'Facebook', 'Oracle']
sort()
可以对当前Array
进行排序,它会直接修改当前Array
的元素位置,直接调用时,按照默认顺序排序reverse()
把整个Array
的元素给掉个个,也就是反转concat()
方法把当前的Array
和另一个Array
连接起来,并返回一个新的Array
join()
方法是一个非常实用的方法,它把当前Array
的每个元素都用指定的字符串连接起来,然后返回连接后的字符串
var arr = ['A', 'B', 'C', 1, 2, 3];
arr.join('-'); // 'A-B-C-1-2-3'
如果Array的元素不是字符串,将自动转换为字符串后再连接。
对象
访问属性是通过.操作符完成的,但这要求属性名必须是一个有效的变量名。如果属性名包含特殊字符,就必须用''括起来,用['xxx']来访问,不推荐使用此种属性名,访问不存在的属性不报错,而是返回undefined
,检测对象是否拥有某一属性,可以用in操作符,不过要小心,如果in判断一个属性存在,这个属性不一定是xiaoming的,它可能是xiaoming继承得到的, 要判断一个属性是否是xiaoming自身拥有的,而不是继承得到的,可以用hasOwnProperty()
方法:
var xiaohong = {
name: '小红',
'middle-school': 'No.1 Middle School'
};
xiaohong['middle-school']; // 'No.1 Middle School'
xiaohong['name']; // '小红'
xiaohong.name; // '小红'
xiaoming.age; // undefined
xiaoming.age = 18; // 新增一个age属性
delete xiaoming.age; // 删除age属性
'name' in xiaoming; // true
'toString' in xiaoming; // true
xiaoming.hasOwnProperty('toString'); // false
循环
for
循环的一个变体是for ... in
循环,它可以把一个对象的所有属性依次循环出来, for ... in
对Array
的循环得到的是String
而不是Number
ES6标准引入了新的iterable
类型,Array
、Map
和Set
都属于iterable类型。
具有iterable
类型的集合可以通过新的for ... of
循环来遍历。
var a = ['A', 'B', 'C']
a.name = 'Hello';
for (var x in a) {
alert(x); // '0', '1', '2', 'name'
}
这就是为什么要引入新的for ... of
循环
然而,更好的方式是直接使用iterable
内置的forEach
方法,它接收一个函数,每次迭代就自动回调该函数,以Array
为例:
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
alert(element);
});
- Map的回调函数参数依次为value、key和map本身
- Set与Array类似,但Set没有索引,因此回调函数的前两个参数都是元素本身
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
alert(value);
});
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
alert(element);
});
不需要使用全部的参数
STL-Map&Set
初始化Map需要一个二维数组,或者直接初始化一个空Map。Map具有以下方法:
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set:
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.add(4)
>>> s
{1, 2, 3, 4}
>>> s.delete(3)
>>> s
{1, 2, 4}
函数
JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array:
function foo(x) {
alert(x); // 10
for (var i=0; i<arguments.length; i++) {
console.log(arguments[i]); // 10, 20, 30
}
}
foo(10, 20, 30);
实际上arguments最常用于判断传入参数的个数
ES6标准引入了rest参数
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
rest参数只能写在最后,前面用...
标识,从运行结果可知,传入的参数先绑定a、b,多余的参数以数组形式交给变量rest
作用域
var变量作用域是在函数内部, let变量,const常量作用域是所属块
变量提升
JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明变量的声明“提升”到函数顶部
全局作用域
不在任何函数内定义的变量就具有全局作用域。实际上,JavaScript默认有一个全局对象window
,全局作用域的变量实际上被绑定到window
的一个属性
名字空间
全局变量会绑定到window
上,不同的JavaScript文件如果使用了相同的全局变量,或者定义了相同名字的顶层函数,都会造成命名冲突,并且很难被发现。
减少冲突的一个方法是把自己的所有变量和函数全部绑定到一个全局变量中。例如:
// 唯一的全局变量MYAPP:
var MYAPP = {};
// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 其他函数:
MYAPP.foo = function () {
return 'foo';
};
方法
在一个方法内部,this
是一个特殊变量,它始终指向当前对象,而在函数内部定义的函数,this
又指向undefined
了!(在非strict
模式下,它重新指向全局对象window
!)
apply
要指定函数的this指向哪个对象,可以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数
另一个与apply()类似的方法是call(),唯一区别是:
- apply()把参数打包成Array再传入;
- call()把参数按顺序传入。
也可以用此函数改变函数的行为
var count = 0;
var oldParseInt = parseInt; // 保存原函数
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};
// 测试:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3
高阶函数
JavaScript的函数其实都指向某个变量,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数
map&reduce
传入一个函数参数, 作用于数组中的每一个元素Array.map(parameter)
function pow(x) {
return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
传入一个函数参数, 作用于每一个元素和上一个元素的函数值Array.reduce(parameter)
[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)
f(x) = g(f(x-1), x);
笔记会继续更新,感谢关注
参考资料
廖雪峰_JavaScript教程