JavaScript基础学习
这篇文章是我自己在学习廖雪峰大神的JavaScript教程关于JavaScript的总结,后续会补上全部的总结笔记。
主要用于我自己日后的快速回顾检索重点知识用的。
结合自身,这篇笔记对于有JavaSE基础的人来说,可以达到极速入门JavaScript的效果(毕竟java和JavaScript有很多相似的地方)
笔记对于重复的部分不做描述,重点放在JS的特性上,所以也命名为面向Android的JS学习
如有理解错误的地方,希望大家可以踊跃指出,我立即修改
@(JavaScript)
目录
- 数据类型
- 字符串
- 数组
- 对象
- 条件判断
- 循环
- 集合
- 函数
- 定义
- 调用
- argument
- rest
- return
- 变量作用域
- 局部作用域
- 变量提升
- 全局作用域
- 命名空间
- 常量
- 方法
- this
- apply 和 call
数据类型
- number
- 基本:整数,浮点数,科学计数法,负数
- NaN : not a number,只能用isNaN()来判断
- Infinity : 表示无限大,超过了Number所能表示的最大值
- 字符串
- 布尔值
- null
- undefined
- Number String Null Undefined Boolean 是JS的基本数据类型
- 数组
- 直接赋值会自动填充如:arr[10],缺省的部分自动填充undefined
- 比较运算符
- 使用===代替==,==会自动转换类型,而===不会自动转换
- 运算符顺序:算术运算符 > 比较运算符 > 逻辑运算符 > 赋值运算符
- 对象
- 变量
- 动态编译,所以全部指定为var, 不指定就为全局变量
字符串
- 换行:\n, 或者直接换行(在ES6才能直接使用)
- 拼接: + 或者 var name = 'hello'; ${name}
- 操作:
- str.length
- str[num] , 不能直接通过下标修改字符串
- toUpperCase() 大写转换
- toLowerCase() 小写转换
- indexOf() 检索
- substring() 截取
数组
-
常规属性不做描述了,数组大小是动态改变的
var arr = [1, 'hello', 3];
arr.length; // 3
arr.length = 6;
arr; // arr变为[1, 'hello', 3, undefined, undefined, undefined]
arr[7] = 4;
arr; // arr变为[1, 'hello', 3, undefined, undefined, undefined, undefined, 4]
arr.length = 2;
arr; // arr变为[1, 'hello']
- indexOf() 检索
- slice() 等于 substring() 截取
- push() 和 pop() 参考队列使用,入队和出队
- unshift() 和 shift() 头部的 入队 和 出队
- sort() 排序 ,number自动转换成String,String按照ASCII排序
- reverse() 反转
- splice() 万能方法:
- 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']
- concat() 拼接字符串
- join() 使数组每个字符串用指定字符串连接
- 如果Array的元素不是字符串,将自动转换为字符串后再连接。
var arr = ['A', 'B', 'C', 1, 2, 3];
arr.join('-'); // 'A-B-C-1-2-3'
对象
- JavaScript的对象是一种无序的集合数据类型,它由若干键值对组成
- 键值对: 属性:属性名
- 属性使用:
var xiaohong = {
name: '小红',
'middle-school': 'No.1 Middle School'
};
//属性使用
xiaohong['middle-school']; // 'No.1 Middle School'
xiaohong['name']; // '小红'
xiaohong.name; // '小红'
- JavaScript对象是动态类型,所以可以动态添加属性
bean.age=18; // 这样属性就添加成功了
delete bean.age ; // 删除属性成功
- in字符检测 对象是否包含属性
age in bean // true or false
条件判断
JS中的if...else...的使用和Java基本一样
- 如果不加{}使用的话, if...else...只能作用他下面的第一行
var age = 20;
if (age >= 18)
alert('adult');
else
console.log('age < 18'); // 添加一行日志
alert('teenager'); // <- 这行语句已经不在else的控制范围了
- 在if..else if...else...的多行条件判断下,前面满足条件就不会执行后面的情况了
循环
-
for循环
var x = 0;
var i;
for (i=1; i<=100; i++) {
x = x + i;
}
x; // 5050
1: i = 1; 初始条件,执行一次
2:i <=100 ; 判断条件 ,不满足就退出循环
3: x = x+i ; 具体循环的业务逻辑
4: x++; 每次循环的递增条件
!!所以循环的顺序是
1 > 2 > 3 > 4 > 2 > 3 > 4 > 2 ...... > 2(不满足条件 ,退出循环)
- for...in (比较像Java的foreach)
- 遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。
- 对 对象遍历
var o = {
name: 'Jack',
age: 20,
city: 'Beijing'
};
for (var key in o) {
if (o.hasOwnProperty(key)) { //判断是否包含KEY
alert(key); // 'name', 'age', 'city'
}
}
- 对数组遍历(遍历 得到的是String而不是number)
var a = ['A', 'B', 'C'];
for (var i in a) {
alert(i); // '0', '1', '2'
alert(a[i]); // 'A', 'B', 'C'
}
- while 和 do..while (和Java基本一样这里不赘述了)
集合
是在ES6以后才引入的
-
Map :优点查询快,无论集合多大,检索速度基本不变
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95
m.set('Tom',65); //动态设置, 一个key只能对应一个值,
m.has('Tom'); //是否存在KEY, 返回 布尔值
m.delete('Adam'); //删除
- Set :只储存key,不储存value,同时会把 重复的key自动过滤
var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}
s.add(3);
s; // Set {1, 2, 3, "3"}
s.delete(3);
s; // Set {1, 2, "3"}
- iterable
- for...of :用法本身跟for...in一样,但是却修复了如下问题:
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
alert(x); // '0', '1', '2', 'name'
}
for (var x of a) {
alert(x); // 'A', 'B', 'C'
}
- foreach :
- 对于set因为没有value,所以下面的element和index是 一致的
- JS中对于参数可以不一致,所以是可以只穿一个自己需要的参数
var a = ['A', 'B', 'C'];
a.forEach(function (element, index, array) {
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
alert(element);
});
a.forEach(function (element) {
alert(element);
});
函数
定义
-
正常定义
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
function 指出这是一个函数定义;
abs 是函数的名称;
(x) 括号内列出函数的参数,多个参数以,分隔;
{ ... } 之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
return 返回值,可以没有:返回undefined
- 匿名定义
var abs = function (x) {
if (x >= 0) {
return x;
} else {
return -x;
}
};
与正常定义完全等价,值已经赋给abs了
注意别忘了最后的 ' ; '
调用
- 传参 :
- 可以传多个参数,不过只会使用前面有效的
- 也可以不传,就等于传入了undefined
function abs(x) {
//控制传入参数类型
if (typeof x !== 'number') {
throw 'Not a number';
}
...
}
argument
- 定义:关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array
- 使用:利用arguments,你可以获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值
- 常用于判断传入参数的个数
function abs() {
if (arguments.length === 0) {
return 0;
}
var x = arguments[0];
return x >= 0 ? x : -x;
}
abs(); // 0
abs(10); // 10
abs(-9); // 9
rest
- 定义: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 []
return
- 由于JavaScript引擎在行末自动添加分号的机制,所以代码如下:
function foo() {
return; // 自动添加了分号,相当于return undefined;
{ name: 'foo' }; // 这行语句已经没法执行到了
}
应改为
function foo() {
return { // 这里不会自动加分号,因为{表示语句尚未结束
name: 'foo'
};
}
变量作用域
局部作用域:
- 在函数内定义的变量
- 这个和java比较相似,就是优先使用最靠近的{}里面的变量
- 不同的是,for循环中无法定义局部作用域的变量
所以在ES6中引入了 let,就可以在for中定义了,如下:
function foo() {
for (var i=0; i<100; i++) {
//
}
i += 100; // 仍然可以引用变量i
}
function foo() {
var sum = 0;
for (let i=0; i<100; i++) {
sum += i;
}
i += 1; // 还没定义无法使用,报错
}
变量提升
- 先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部
function foo() {
var x = 'Hello, ' + y;
alert(x);
var y = 'Bob';
}
//这样的代码实际上在JavaScript眼中是这样的
function foo() {
var y; // 提升变量y的申明
var x = 'Hello, ' + y;
alert(x);
y = 'Bob';
}
全局作用域
- 不在函数内定义的变量就是全局的
- JavaScript默认有一个全局对象window,全局变量都是绑定在window上的一个属性
- 函数实际也是一个全局变量
var course = 'Learn JavaScript';
alert(course); // 'Learn JavaScript'
alert(window.course); // 'Learn JavaScript'
function foo() {
alert('foo');
}
foo(); // 直接调用foo()
window.foo(); // 通过window.foo()调用,一样的效果
命名空间
- 由来:因为全局变量都绑定在 window上,当不同JS文件 使用了相同的变量就会产生冲突
- 解决:将变量绑定到一个全局变量中
// 唯一的全局变量MYAPP:
var MYAPP = {};
// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;
// 其他函数:
MYAPP.foo = function () {
return 'foo';
};
常量
- ES6中引入const关键字表示常量
- 与let相同,同时块级作用域
方法
- 一个对象中绑定函数,成为这个对象的方法
this
- 特殊变量,始终指向当前对象
- this指向的问题:
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25, 正常结果
getAge(); // NaN
var fn = xiaoming.age; // 先拿到xiaoming的age函数
fn(); // NaN
造成上面的原因:this指向动态改变,当在全局调用的时候this就指向了window,显然window没有birth属性。
解决办法:始终 使用 正确对象 . 方法(属性 )
- 关键:函数内定义函数:
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - this.birth;
}
return getAgeFromBirth();
}
};
xiaoming.age(); //Uncaught TypeError: Cannot read property 'birth' of undefined
//原因:this指向的匿名函数内部也不存在birth
//解决办法:捕获this
age: function () {
var that = this; // 在方法内部一开始就捕获this
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth; // 用that而不是this
}
return getAgeFromBirth();
}
apply 和 call
- 用于控制this的指向
- apply(this指向对象,参数数组)
- call(this指向对象,参数1,参数2.......)
- 用法:
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, 参数为空
getAge.call(xiaoming,null);
- apply的应用:装饰器:
var count = 0;
var oldParseInt = parseInt; // 保存原函数
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 调用原函数
};
// 测试:
parseInt('10');
parseInt('20');
parseInt('30');
count; // 3
最后:
第一部分的基础快速学习笔记就到这里,如果需要带目录的MD格式笔记可以私信我或者评论,我都可以发给你
如果觉得有那么一点帮助的朋友可以点一下赞鼓励一下
后续进阶部分学习笔记,我会尽快补充上的