0%

JavaScript学习

JavaScript学习

time:2020/04/10

Javascript基础

数据类型和变量

1
2
3
4
5
6
7
8
9
10
//Number类型,不区分整数和浮点数统一为Number类型。
//NaN和Infinity是特殊的Number类型
//一个表示无法表示的数,另一个则是在JavaScript中超过最大能表示的范围,就为Infinity
//%取模运算在JavaScript中可以对浮点数使用
10.5%3==1.5;
0/0==NaN;
2/0==Infinity;
//==和===运算符,前者会自动转换类型再比较,所以应坚持使用后者进行比较
//NaN和所有值都不同,包括其自身,需使用isNaN()来判断
//浮点数的比较也需要注意,eg.1/3!=1-2/3

字符串

1
2
3
4
5
6
7
8
9
10
11
//可用`...`来表示多行字符串
`这是一个
多行
字符串`;
//除了用'+'连接字符串,还可以使用${}来实现
var name = '小明';
var age = 20;
var message = `你好, ${name}, 你今年${age}岁了!`;
//var message = '你好, ' + name + ', 你今年' + age + '岁了!';
//字符串可以使用下标访问特定位置的字符。
//字符串是不变的,所以对某位置的字符进行改变,全字符串是不变的

time:2020/04/16

数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//可以直接给Array的length赋值,并且会改变Array的大小
//可以给Array超过范围的索引赋值,同样会改变Array
//indexOf()方法,可以返回一个索引或者返回索引对应的元素,即参数可以是索引也可以是元素
//slice()方法,就是和string的substring方法是同样的效果,且参数是参数包含开始索引不包含结束索引,不传递参数,则代表剪切整个字符串,可以这样复制数组
//push()和pop()方法,字符串末尾添加或者删除元素
//unshift()和shift()方法,字符串开头添加或者删除元素(unshift添加)
//sort()方法,排序;reverse()方法,调转数组。
var arr={'A','b'};
arr.sort();
//splice()方法,第一个参数指定索引,第二个参数指定从该索引开始删除的元素个数,然后后面可以跟一些字符串表示从该索引开始添加的元素,也可以不添加,即只有两个参数。并且该方法会返回删除的元素形成的数组
var arr = ['Microsoft', 'Apple', 'Yahoo', 'AOL', 'Excite', 'Oracle'];
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']
//concat方法,连接两个数组并返回新数组
var c=a.concat(b);
//join方法,把数组中的元素用特定的字符串连接起来,返回字符串
var arr = ['A', 'B', 'C', 1, 2, 3];
arr.join('-'); // 'A-B-C-1-2-3',可以是字符串 不一定只有一个字符

对象

1
2
3
4
5
6
7
8
9
var stu = {
name:'小小'
};
stu.name;
stu['name']; //这两种访问都是可以的
stu.number = '153'; //可以动态添加属性
delete stu.number; //删除属性
'name' in stu; //检查对象是否拥有某属性,或者其是否继承某属性 布尔型
stu.hasOwnProperty('name'); //检查自身是否拥有某一属性 布尔型

循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//条件判断语句if else与常规语言没有什么区别
//for循环的基本使用也都一样
//for...in...,可以将一个对象的所有属性都循环一遍
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
console.log(key); // 'name', 'age', 'city'
}
//要过滤掉对象继承的属性,用hasOwnProperty()来实现
//Array也是对象,也可以使用for..in..循环,循环得到的是索引
//需要注意,得到的索引是String而不是Number

Map和Set

1
2
3
4
5
6
7
8
9
10
11
12
13
//Map
//初始化map需要一个二维数组,或者可以初始化为空
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
var m = new Map(); // 空Map
m.set('Adam', 67);//通过set方法添加键值对
m.get('Adam');//通过get方法取得键对应的值
m.has('Adam'); //通过has方法检查是否存在键 布尔型
m.delete('Adam'); //通过delete方法删除键值对
//由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉
//Set
//要创建一个Set,需要提供一个Array作为输入,或者直接创建一个空Set
//重复元素在Set中自动被过滤
//通过add(key)方法可以添加元素到Set中,可以重复添加,但不会有效果;通过delete(key)方法可以删除元素

time:2020/04/18

iterable

1
2
3
4
5
6
7
8
9
10
11
12
//for..of..迭代器循环
//可用来遍历array的所有元素
//forEach()方法
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
console.log(element);
});
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
console.log(value);
});
//需要提供回调函数function,对每个元素都执行一遍function

函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//javascrpit中函数也可以看作对象,函数名可以认为是指向该函数的变量
var abs = function (x) {
if (x >= 0) return x;
else return -x;
};
//允许传入多个参数,没有定义的参数传入也不会改变什么,传入的参数少也是可以的
//没有参数传入,函数内部的参数接收到的就是undefined,可以在函数内部进行检查以避免
//javascript函数中存在默认参数arguments,里面存放了所有参数,为Array类型
//而且就算函数不定义参数,如果传入了参数,也可以通过arguments拿到参数值
//还可以利用arguments拿到传入参数的个数
//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 ]
//如果没有多余的参数,rest就会接受一个空数组

变量作用域与解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//变量提升
//javascript的函数中会自动把变量的声明提到函数顶部,但不会把赋值提前进行
function foo() {
var x = 'Hello, ' + y;
console.log(x);
var y = 'Bob';
}
//不会报错,但是打印的y是undefined
//由于JavaScript的这一怪异的“特性”,我们在函数内部定义变量时,请严格遵守“在函数内部首先申明所有变量”这一规则。
//最常见的做法是用一个var申明函数内部用到的所有变量
//不在任何函数内定义的变量就具有全局作用域。
//实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性
//可以通过window.变量进行访问该变量
//某些函数也同样是全局的,可通过window进行访问
//局部作用域
//由于JavaScript的变量作用域实际上是函数内部,我们在for循环等语句块中是无法定义具有局部作用域的变量的
//为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量
//ES6标准引入了新的关键字const来定义常量,const与let都具有块级作用域
const PI = 3.14;
//解构赋值
//从ES6开始,JavaScript引入了解构赋值,可以同时对一组变量进行赋值。
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
//注意,对数组元素进行解构赋值时,多个变量要用[...]括起来。
//如果数组本身还有嵌套,也可以通过下面的形式进行解构赋值,注意嵌套层次和位置要保持一致:
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
//解构赋值还可以忽略某些元素:
let [, , z] = ['hello', 'JavaScript', 'ES6'];
//如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性:
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};
var {name, age, passport} = person;
//使用解构赋值对对象属性进行赋值时,如果对应的属性不存在,变量将被赋值为undefined
//如果要使用的变量名和属性名不一致,可以用下面的语法获取:
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678',
school: 'No.4 middle school'
};

// 把passport属性赋值给变量id:
let {name, passport:id} = person
//解构赋值还可以使用默认值,这样就避免了不存在的属性返回undefined的问题:
var person = {
name: '小明',
age: 20,
gender: 'male',
passport: 'G-12345678'
};

// 如果person对象没有single属性,默认赋值为true:
var {name, single=true} = person;
name; // '小明'
single; // true
//有些时候,如果变量已经被声明了,再次赋值的时候,正确的写法也会报语法错误:
var x, y;
// 解构赋值:
{x, y} = { name: '小明', x: 100, y: 200};
// 语法错误: Uncaught SyntaxError: Unexpected token =
//这是因为JavaScript引擎把{开头的语句当作了块处理,于是=不再合法。解决方法是用小括号括起来:
({x, y} = { name: '小明', x: 100, y: 200});
//解构赋值在很多时候可以大大简化代码。例如,交换两个变量x和y的值,可以这么写,不再需要临时变量:
var x=1, y=2;
[x, y] = [y, x]
//如果一个函数接收一个对象作为参数,那么,可以使用解构直接把对象的属性绑定到变量中。例如,下面的函数可以快速创建一个Date对象:
function buildDate({year, month, day, hour=0, minute=0, second=0}) {
return new Date(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second);
}
//它的方便之处在于传入的对象只需要year、month和day这三个属性:
buildDate({ year:2017, month:1, day:1 });

方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//JavaScript的函数内部如果调用了this,那么这个this到底指向谁?
//如果是通过对象的形式进行调用,那么this指向的是调用的对象,是符合情理的
//如果单独调用函数,比如getAge(),此时,该函数的this指向全局对象,也就是window。
//要保证this指向正确,必须用obj.xxx()的形式调用!
//也可以先使用that捕获this,然后再使用
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var that = this; // 在方法内部一开始就捕获this
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth; // 用that而不是this
}
return getAgeFromBirth();
}
};
//这样就能避免出错了
//apply
//指定函数的this指向哪个对象,可以用函数本身的apply方法
//它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数。
//使用apply来避免this的出错
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}

var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};

xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空
//另一个与apply()类似的方法是call(),唯一区别是:
//apply()把参数打包成Array再传入;
//call()把参数按顺序传入。
Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
//对普通函数调用,我们通常把this绑定为null
//装饰器
//利用apply(),我们还可以动态改变函数的行为。
//现在假定我们想统计一下代码一共调用了多少次parseInt(),
//可以把所有的调用都找出来,然后手动加上count += 1,
//不过这样做太傻了。最佳方案是用我们自己的函数替换掉默认的parseInt()
var count = 0;
var oldParseInt = parseInt; // 保存原函数

window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};

闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
//Array的map()方法
//传入参数为函数对象,作用为将此函数作用于数组的所有元素
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
//reduce()方法
//Array的reduce()把一个函数作用在这个Array的[x1, x2, x3...]上
//这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算,其效果就是:
[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 * 10 + y;
}); // 13579,reduce的一些好用的地方
//可以省略function,进而变成arr.map(x=>10*x)或者arr.reduce((x,y)=>10*x+y)

箭头函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//使用箭头函数来省略function
x=>x*x;
function(x){return x*x;};//两者等价
//箭头函数相当于匿名函数
//如果函数只用return一个表达式,则可以全部省略
//如果函数体里包含了一些其他结构,则不能省略return
x => {
if (x > 0) return x * x;
else return - x * x;
}
//如果存在多个参数需要用括号括起来
(x, y) => x * x + y * y
() => 3.14
// 可变参数:
(x, y, ...rest) => {
var i, sum = x + y;
for (i=0; i<rest.length; i++) {
sum += rest[i];
}
return sum;
}
//在返回对象的时候需要用小括号括起来,因为{}会导致歧义
x=>({foo : x});
//使用箭头函数也不用担心this的错用,箭头函数会保证this指向外部作用域
//this在箭头函数中已经词法绑定了
//用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略
arr.sort((x, y) => {
return x-y;
});//简化sort写法
console.log(arr); // [1, 2, 10, 20]

generator