学习javascript的笔记
主要学习了
JavaScript教程
字符串
多行字符串
这是一个
多行
字符串
;
toUpperCase()
,toLowerCase()
把一个字符串全部变为大写或小写
1 2 3
| var s = 'Hello'; s.toUpperCase(); s.toLowerCase();
|
indexOf()
搜索指定字符串出现的位置
1 2 3
| var s = 'hello, world'; s.indexOf('world'); s.indexOf('World');
|
substring()
返回指定索引区间的子串
1 2 3
| var s = 'hello, world' s.substring(0, 5); s.substring(7);
|
数组
通过Array.length
获取数组长度,给length赋一个新的值或索引赋值时索引超过了范围,会导致Array大小的变化
1 2 3 4 5 6
| var arr = [1, 2, 3.14]; arr.length; arr.length = 4; arr; arr[5] = 'x'; arr;
|
通过indexOf()
来搜索Array中一个指定的元素的位置
1 2 3
| var arr = [10, 20, '30', 'xyz']; arr.indexOf(10); arr.indexOf(30);
|
通过slice()
截取Array的部分元素,然后返回一个新的Array
1 2 3
| var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G']; arr.slice(0, 3); arr.slice(3);
|
push()
向Array的末尾添加若干元素,pop()
则把Array的最后一个元素删除掉,unshift()
往Array的头部添加若干元素,shift()
则把Array的第一个元素删掉
1 2 3 4 5 6 7 8 9 10 11 12
| var arr = [1, 2]; arr.push('A', 'B'); arr; arr.pop(); arr; arr.unshift('A', 'B'); arr; arr.shift(); arr; arr = []; arr.pop(); arr.shift();
|
sort()
, reverse()
可以对当前Array进行排序,它会直接修改当前Array的元素位置,直接调用时,按照默认把所有元素先转换为String,再根据ASCII码进行排序
1 2 3 4 5
| var arr = ['B', 'C', 'A', 'b']; arr.sort(); arr; arr.reverse(); arr;
|
splice()
方法可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素:
1 2 3 4 5 6 7 8 9 10
| var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle']; arr.splice(2, 3, 'Google', 'Facebook'); arr; arr.splice(2, 2); arr; arr.splice(2, 0, 'Google', 'Facebook'); arr;
|
concat()
方法把当前的Array和另一个Array连接起来,并返回一个新的Array:
1 2 3
| var arr = ['A', 'B', 'C']; arr.concat(1, 2, [3, 4]); arr;
|
join()
方法把当前Array的每个元素都用指定的字符串连接起来,然后返回连接后的字符串:
1 2 3
| var arr = ['A', 'B', 'C', 1, 2, 3]; arr.join('-'); arr.join('');
|
如果数组的某个元素又是一个Array,则可以形成多维数组
1 2
| var arr = [[1, 2, 3], [400, 500, 600], '-']; arr[1][1];
|
对象
JavaScript的对象是一种无序的集合数据类型,它由若干键值对组成。访问属性是通过.
操作符完成的,但这要求属性名必须是一个有效的变量名。如果属性名包含特殊字符,就必须用’’括起来
1 2 3 4 5 6 7 8 9 10 11 12
| var xiaoming = { name: '小明', birth: 1990, school: 'No.1 Middle School', height: 1.70, weight: 65, score: null }; xiaohong['middle-school']; xiaohong['name']; xiaohong.name; xiaoming.age;
|
要检测xiaoming是否拥有某一属性,可以用in
操作符。因为toString
定义在object对象中,所以xiaoming继承了toString
属性;可以用hasOwnProperty()
方法判断一个属性是否是xiaoming自身拥有的,而不是继承得到的。
1 2 3 4 5 6
| var xiaoming = { name: '小明' }; 'toString' in xiaoming; xiaoming.hasOwnProperty('name'); xiaoming.hasOwnProperty('toString');
|
条件判断
使用if () { ... } else { ... }
来进行条件判断,else if
通常连写在一起,以增加可读性。
1 2 3 4 5 6 7 8
| var age = 3; if (age >= 18) { console.log('adult'); } else if (age >= 6) { console.log('teenager'); } else { console.log('kid'); }
|
循环
for循环最常用的地方是利用索引来遍历数组
1 2 3 4 5 6
| var arr = ['Apple', 'Google', 'Microsoft']; var i, x; for (i=0; i<arr.length; i++) { x = arr[i]; console.log(x); }
|
for循环的3个条件都是可以省略的,但必须使用break
语句退出循环,否则就是死循环
1 2 3 4 5 6 7
| var x = 0; for (;;) { if (x > 100) { break; } x ++; }
|
for ... in
循环可以把一个对象的所有属性依次循环出来
1 2 3 4 5 6 7 8
| var o = { name: 'Jack', age: 20, city: 'Beijing' }; for (var key in o) { console.log(key); }
|
for ... in
循环可以直接循环出Array的索引,但得到索引的是String而不是Number
1 2 3 4 5
| var a = ['A', 'B', 'C', 1, 2, 3]; for (var i in a) { console.log(i) console.log(a[i]); }
|
while循环只有一个判断条件,条件满足,就不断循环,条件不满足时则退出循环
1 2 3 4 5 6 7
| var x = 0; var n = 99; while (n > 0) { x = x + n; n = n - 2; } x;
|
do { ... } while()
循环,它和while循环的唯一区别在于前者是在每次循环完成的时候判断条件,所以至少会执行一次循环
1 2 3 4 5
| var n = 0; do { n = n + 1; } while (n < 100); n;
|
Map和Set
Map
是一组键值对的结构,具有极快的查找速度,Map
具有以下方法:
1 2 3 4 5 6 7 8
| var M = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]); var m = new Map(); m.set('Adam', 67); m.set('Bob', 59); m.has('Adam'); m.get('Adam'); m.delete('Adam'); m.get('Adam');
|
Set
是一组key
的集合,不能重复,重复元素在Set
中自动被过滤
1 2 3 4 5 6
| var s = new Set([1, 2, 3, 3, '3']); s; s.add(4); s.delete(2); s.size; s.has(3);
|
iterable
for ... of
循环来遍历Array
、Map
和Set
1 2 3 4 5 6 7 8 9 10 11 12
| var a = ['A', 'B', 'C']; var s = new Set(['A', 'B', 'C']); var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]); for (var x of a) { console.log(x); } for (var x of s) { console.log(x); } for (var x of m) { console.log(x[0] + '<=>' + x[1]); }
|
iterable
内置的forEach方法,它接收一个函数,每次迭代就自动回调该函数,以下是Array的例子
1 2 3 4 5 6 7
| var a = ['A', 'B', 'C']; a.forEach(function (element, index, array) { console.log("element: " + element + "; index: " + index + "; array: " + array); });
|
Set
与Array
类似,但Set
没有索引,因此回调函数的前两个参数都是元素本身
1 2 3 4
| var s = new Set(['A', 'B', 'C']); s.forEach(function (element, sameElement, set) { console.log("element: " + element + "; sameElement: " + sameElement + "; set: " + set); });
|
Map
的回调函数参数依次为value
、key
和map
本身
1 2 3 4
| var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]); m.forEach(function (value, key, map) { console.log("value: " + value + "; key: " + key + "; map: " + map); });
|
函数定义和调用
1 2 3 4 5 6 7 8
| function abs(x) { return x>0 ? x : -x; } var abs = function (x) { return x>0 ? x : -x; };
|
利用arguments
获取所有传入参数
1 2 3 4 5 6 7 8 9 10
| function abs() { if (arguments.length === 0) { return 0; } if (typeof x !== 'number') { throw 'Not a number'; } var x = arguments[0]; return x >= 0 ? x : -x; }
|
使用rest
来获取任意个参数,需写在最后面,前面加...
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function foo(a, b, ...rest) { console.log('a = ' + a); console.log('b = ' + b); console.log(rest); } function sum(x, ...rest) { let tmp = 0; if(x) tmp += x; for(let i of rest){ tmp += i; } return tmp; }
|
## 变量作用域
var
定义变量,该变量的作用域为整个函数体。不在任何函数内定义的变量就具有全局作用域,被绑定到全局对象window的一个属性
1 2 3 4 5 6 7 8 9
| 'use strict'; var course = 'Learn JavaScript'; console.log(course); console.log(window.course); function foo() { console.log('you foo'); } foo(); window.foo();
|
ES6引入了新的关键字let
,用let
替代var
可以申明一个块级作用域(for循环等)的变量
1 2 3 4 5 6 7
| function foo() { var sum = 0; for (let i=0; i<100; i++) { sum += i; } return sum; }
|
ES6标准引入了新的具有块级作用域的关键字const
来定义常量
1 2 3
| const PI = 3.14; PI = 3; PI;
|
方法
在一个对象中绑定函数,称为这个对象的方法,在一个方法内部,this
是一个特殊变量,它始终指向当前对象
1 2 3 4 5 6 7 8 9
| var xiaoming = { name: '小明', birth: 1990, age: function () { var y = new Date().getFullYear(); return y - this.birth; } }; xiaoming.age();
|
apply()
可以指定函数的this
的指向
1 2 3 4 5 6 7 8 9 10 11
| function getAge() { var y = new Date().getFullYear(); return y - this.birth; } var xiaoming = { name: '小明', birth: 1990, age: getAge }; xiaoming.age(); getAge.apply(xiaoming, []);
|
call()
方法与apply()
类似
apply()把参数打包成Array再传入;
call()把参数按顺序传入。
1 2
| Math.max.apply(null, [3, 5, 4]); Math.max.call(null, 3, 5, 4);
|
利用apply()
动态改变函数的行为,如通过用我们自己的函数替换掉默认的parseInt()的方法统计代码一共调用了多少次parseInt()
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var count = 0; var oldParseInt = parseInt; window.parseInt = function () { count += 1; return oldParseInt.apply(null, arguments); }; parseInt('10'); parseInt('20'); for(let x=0;x<10;x++){ parseInt('30'); } count;
|
高阶函数
map()
方法将array内的每一个元素一次处理
1 2 3 4 5 6 7
| function pow(x) { return x * x; } var arr = [1, 2, 3]; arr.map(pow); arr.map(String);
|
reduce()
方法把一个函数作用在这个Array的[x1, x2, x3…]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算
1 2 3 4 5 6 7 8 9 10 11
| [x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4) var arr = [1, 3, 5, 7, 9]; arr.reduce(function (x, y) { return x + y; }); function string2int(s) { return s.split("").map(function(x){return x-0}).reduce(function(x,y){return x*10+y}); } string2int("23434");
|
filter()
方法把传入的函数依次作用于array的每个元素,然后根据返回值是true还是false决定保留还是丢弃该元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| var arr = ['A', '', 'B', null, undefined, 'C', ' ']; var r = arr.filter(function (s) { return s && s.trim(); }); arr; var arr = ['A', 'B', 'C']; var r = arr.filter(function (element, index, self) { console.log(element); console.log(index); console.log(self); return true; }); var r, arr = ['1', '1', '2', '3', '2', '4', '5', '1']; r = arr.filter(function (element, index, self) { return self.indexOf(element) === index; });
|
sort()
方法默认把所有元素先转换为String再以ASCII排序,直接使用对数字排序会有大Bug,可通过自定义方式解决问题。
sort()
方法会直接对Array进行修改,它返回的结果仍是当前Array
1 2 3 4 5 6 7 8 9 10 11 12 13
| var arr = [10, 20, 1, 2]; a2 = arr.sort(function (x, y) { if (x < y) { return -1; } if (x > y) { return 1; } return 0; }); a2 = arr;
|
闭包
闭包就是能够读取其他函数内部变量的函数,由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁
1 2 3 4 5 6 7 8 9 10 11 12 13
| function f1(){ var n=999; nAdd=function(){n+=1}; function f2(){ console.log(n); } return f2; } var result=f1(); result(); nAdd(); result();
|
箭头函数
ES6标准新增了一种新的函数:Arrow Function(箭头函数)
1 2 3 4 5
| x => x * x function (x) { return x * x; }
|
箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj
1 2 3 4 5 6 7 8 9
| var obj = { birth: 1990, getAge: function () { var b = this.birth; var fn = () => new Date().getFullYear() - this.birth; return fn(); } }; obj.getAge();
|
generator
generator(生成器)是ES6标准引入的新的数据类型,使用function*定义。一个generator看上去像一个函数,但可以返回多次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function* fib(min,max) { var t, a = 0, b = 1, n = 1; while (n <= max) { if(n >= min){ yield a; } t = a + b; a = b; b = t; n ++; } return a; } for (let x of fib(4,5)) { console.log(x); }
|
对象
类型转换和判断需要注意的问题:
用parseInt()
或parseFloat()
来转换任意类型到number
;
用String()
来转换任意类型到string
,或者直接调用某个对象的toString()
方法;
通常不必把任意类型转换为boolean
再判断,因为可以直接写if (myVar) {...}
;
typeof
操作符可以判断出number
、boolean
、string
、function
和undefined
;
判断Array
要使用Array.isArray(arr)
;
判断null
请使用myVar === null
;
判断某个全局变量是否存在用typeof window.myVar === 'undefined'
;
函数内部判断某个变量是否存在用typeof myVar === 'undefined'
。
1 2 3
| 123..toString(); (123).toString();
|
Date 对象
在JavaScript中,Date对象用来表示日期和时间,使用Date()
获取系统时间;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var now = new Date(); now; now.getFullYear(); now.getMonth(); now.getDate(); now.getDay(); now.getHours(); now.getMinutes(); now.getSeconds(); now.getMilliseconds(); now.getTime(); var d = new Date(1970, 0, 1, 7, 59, 59, 999); d; d.getTime(); -1;
|
RegExp
正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的
1 2 3 4
| var MailCheck = /^[0-9a-zA-Z\_\.]+@[0-9a-zA-Z\_]+\.[0-9a-zA-Z\_]+/; MailCheck.exec('juncaixinchi111#gmail.com'); MailCheck.exec('juncaixinchi111@gmail.com');
|
JSON
JSON是JavaScript Object Notation的缩写,它是一种数据交换格式
使用JSON.stringify()
把对象序列化成JSON格式的字符串:
1 2 3 4 5 6 7 8 9 10
| var xiaoming = { name: '小明', age: 14, gender: true, height: 1.65, grade: null, 'middle-school': '\"W3C\" Middle School', skills: ['JavaScript', 'Java', 'Python', 'Lisp'] }; JSON.stringify(xiaoming);
|
按缩进输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| JSON.stringify(xiaoming, null, ' '); { "name": "小明", "age": 14, "gender": true, "height": 1.65, "grade": null, "middle-school": "\"W3C\" Middle School", "skills": [ "JavaScript", "Java", "Python", "Lisp" ] }
|
给对象定义一个toJSON()
的方法,直接返回JSON应该序列化的数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var xiaoming = { name: '小明', age: 14, gender: true, height: 1.65, grade: null, 'middle-school': '\"W3C\" Middle School', skills: ['JavaScript', 'Java', 'Python', 'Lisp'], toJSON: function () { return { 'Name': this.name, 'Age': this.age }; } }; JSON.stringify(xiaoming);
|
使用JSON.parse()
反序列化
1 2 3 4 5 6 7 8 9
| JSON.parse('{"name":"小明","age":14}'); JSON.parse('{"name":"小明","age":14}', function (key, value) { if (key === 'name') { return value + '同学'; } return value; });
|