前端之JavaScript
1.ECMAScript和JavaScript的关系
1996年11月,JavaScript的创造者--Netscape公司,决定将JavaScript提交给国际标准化组织ECMA,希望这门语言能够成为国际标准。次年,ECMA发布262号标准文件(ECMA-262)的第一版,规定了浏览器脚本语言的标准,并将这种语言称为ECMAScript,这个版本就是1.0版。
该标准一开始就是针对JavaScript语言制定的,但是没有称其为JavaScript,有两个方面的原因。一是商标,JavaScript本身已被Netscape注册为商标。而是想体现这门语言的制定者是ECMA,而不是Netscape,这样有利于保证这门语言的开发性和中立性。
因此ECMAScript和JavaScript的关系是,前者是后者的规格,后者是前者的一种实现。
2.JavaScript概述
一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:
- 核心(ECMAScript)
- 文档对象模型(DOM)Document object model(整合js,css,html)
- 浏览器对象模型(BOM) Broswer object model(整合js和浏览器)
简单的说,ECMAScript描述了JavaScript语言本身的相关内容
JavaScript是脚本语言
JavaScript是一种轻量级语言
JavaScript是可插入HTML页面的编程代码
JavaScript插入HTML页面后,可由所有的现代浏览器执行
3.JavaScript引入方式
3.1 Script标签内写代码
<script>
//js代码
</script>
3.2 引入外部js文件
<script src='myscript.js'></script>
4.JavaScript语言规范
4.1 注释(注释是代码之母)
<script>
// 这是单行注释
/*
这是
多行注释
*/
</script>
4.2 结束符
JavaScript中的语句要以;为结束符
5.JavaScript语言基础
5.1 变量声明
JavaScript的变量名可以用_,数字,字母,$组成,不能以数字开头
声明变量使用var 变量名;的格式来进行声明
var name = 'lucas';
var age = 18;
注意:
- 变量名是区分大小写的
- 推荐使用驼峰体命名规则
- 保留字不能用做变量名
补充:
ES6(ECMAScript 6)新增了let命令,用于声明变量,用法类似于var,但是所声明的变量只在let命令所在的代码块有效,例如for循环的计数器就很适合使用let命令
for (let i = 0; i < arr.length; i++){...}
ES6新增const用来声明常量,一旦声明,其值就不能改变
const PI = 3.14159;
PI //3.14159
PI = 3;
// TypeError: "PI" is read-only
6.JavaScript数据类型
JavaScript拥有动态类型
var x; //此时x是undefined
var x = 1 //此时x是数字
var x = 'lucas' //此时x是字符串
6.1 数值(Number)
JavaScript不区分整型和浮点型,就只有一种数字类型
var a = 11.11;
var b = 20;
var c = 123e5; //12300000
var d = 123e-5; //0.00123
还有一种NaN,表示不是一个数字(Not a number)
常用方法:
parseInt('123') //返回是123
parseInt('ABC') //返回NaN,NaN属性是代表非数字值的特殊值,该属性用于指示某个值不是数字
parseInt('123.456') //返回是123
parseFloat('123.456') //返回是123.456
6.2 字符串(string)
var a = 'Hello'
var b = 'World';
var c = a + b;
console.log(c); //得到HelloWorld
常用方法:
方法 | 说明 |
---|---|
.length | 返回长度 |
.trim() | 移除空白 |
.trimLeft() | 移除左边的空白 |
.trimRight() | 移除右边的空白 |
.charAt(n) | 返回第n个字符 |
.concat(value,...) | 拼接 |
.indexOf(substring,start) | 子序列位置 |
.substring(from,to) | 根据索引获取子序列 |
.slice(start,end) | 切片 |
.toLowerCase() | 小写 |
.toUpperCase() | 大写 |
.split(delimiter,limit) | 分割 |
slice和substring的区别
string.slice(start,stop) 和 string.substring(start,stop):
两者的相同点:
如果start等于stop,返回空字符串
如果stop参数省略,则取到字符串末尾
如果某个参数超过string的长度,这个参数会被替换为string的长度
substring()的特点:
如果start>stop,start和stop将被交换
如果参数是负数或者不是数字,将会被0替换
slice()的特点:
如果start>stop,两者不会交换
如果start小于0,则切割从字符串末尾往前数的第start个的字符开始(包括该位置的字符)
var name = 'dswzdcymgmjj'
name.slice(-5,-3); //返回是 mg
如果stop小于0,则切割在从字符串末尾往前数的第stop个字符结束(不包括该位置字符)
name.slice(5,-3); //返回是 cymg
补充:
ES6中引入了模板字符串,模板字符串是增强版的字符串,用反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量
//普通字符串
`这是普通字符串`
//多行文本
`
这是
多行文本
`
//字符串中嵌入变量
var name = 'lucas',time = 'today';
`Hello ${name},how are you ${time}?`
注意:
如果模板字符串中需要使用反引号,则在其前面要用反斜杠转义
6.3 布尔值(Boolean)
区别于python,true和false都是小写
var a = true;
var b = false;
//空字符串、0、null、undefined、NaN都是false
null和undefined区别
- null表示值是空,一般在需要指定或清空一个变量时才会使用,如name=null
- undefined表示当声明一个变量但未初始化时,该变量的默认值是undefined,还有就是函数无明确的返回值时,返回的也是undefined
null表示变量的值是空(null可以手动清空一个变量的值,使得该变量变为object类型,值为null),undefined则表示只声明了变量,但还没赋值
6.4 对象(object)
JavaScript中的所有事物都是对象:字符串、数值、数组、函数...此外,JavaScript允许自定义对象
JavaScript提供多个内建对象,比如String、Date、Array等待
对象只是带有属性和方法的特殊数据类型
6.5 数组
数组对象的作用是:使用单独的变量名来存储一些的值,类似于python中的列表
var a = [123,'abx'];
console.log(a[1]); //输出'abx'
常用方法:
方法 | 说明 |
---|---|
.length | 数组的长度 |
.push(ele) | 尾部追加元素 |
.pop() | 删除列表最后一个元素并有返回值 |
.unshift(ele) | 头部插入元素 |
.shift() | 头部移除元素 |
.slice(start,end) | 切片 |
.reverse() | 反转 |
.join(seq) | 将数组连接成字符串 |
.concat(val,...) | 连接数组 |
.sort() | 排序 |
.forEach() | 将数组的每个元素传递给函数 |
.splice() | 删除元素,并向数组添加新元素 |
.map() | 返回一个处理后的新数组 |
forEach(function(currentValue,index,arr),thisValue)
参数:
- currentValue:必须,当前元素
- index:可选,当前元素的索引值
- arr:可选,当前元素所属的数组对象
- thisValue:可选,传递给函数的值一般用'this',如果这个参数为空,'underfined'会传递给'this'值
var l = [11,22,33,44];
undefined
l.forEach(function(value,index,arr){
console.log(value,index,l)
})
VM1538:2 11 0 (4) [11, 22, 33, 44]
VM1538:2 22 1 (4) [11, 22, 33, 44]
VM1538:2 33 2 (4) [11, 22, 33, 44]
VM1538:2 44 3 (4) [11, 22, 33, 44]
undefined
l.forEach(function(value){
console.log(value)
})
VM1599:2 11
VM1599:2 22
VM1599:2 33
VM1599:2 44
undefined
splice()
语法:
splice(index,howmany,item1,...)
参数:
- index:必需,规定从何处添加/删除元素(必须是数字)
- howmany:必需,规定应该删除多少元素,可以是0,但必须是数字
- item1,...:可选,要添加到数组的新元素
var arr2 = [1,2,3,4,5,6,7];
undefined
arr2.splice(2,2,8,9)
(2) [3, 4]
arr2
(7) [1, 2, 8, 9, 5, 6, 7]
map()
语法:
map(function(currentValue,index,arr),thisValue)
参数:
- currentValue:必需,当前元素的值
- index:可选,当前元素的索引值
- arr:可选,当前元素属于的数组对象
- thisValue:可选,传递给函数的值一般用'this',如果这个参数为空,'underfined'会传递给'this'值
var arr = [11,22,33,44];
undefined
arr.map(function(value,index,arr){
return value + 1;
})
(4) [12, 23, 34, 45]
arr
(4) [11, 22, 33, 44]
arr.map(function(value,index,arr){
return a = value + 1;
})
(4) [12, 23, 34, 45]
a
45 //return 有多个值得话只返回最后一个
arr
(4) [11, 22, 33, 44]
关于sort需要注意:
如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码的顺序进行排序。要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以便进行比较。
如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:
若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
若 a 等于 b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。
function sortNumber(a,b){
return a - b
}
var arr1 = [11, 100, 22, 55, 33, 44]
arr1.sort(sortNumber)
7.运算符
7.1 算数运算符:+,-,*,/,%,++,--
var x = 10;
undefined
var res1 = x++
undefined
var res2 = ++x
undefined
res1
10
res2
12
//x++先赋值再自增1运算,而++x会先进行自增运算再赋值
7.2 比较运算符:>, >=, <, <=, !=, ==, =, !
注意:
1 == '1' //true 弱等于
1 ==='1' //false 强等于
//上面这张情况出现的原因在于JS是一门弱类型语言(会自动转换数据类型),所以当你用两个等号进行比较时,JS内部会自动先将
//数值类型的1转换成字符串类型的1再进行比较,所以我们以后写JS涉及到比较时尽量用三等号来强制限制类型,防止判断错误
7.3 逻辑运算符:&&, ||, !
var w = 10;
undefined
var z = 20;
undefined
w && z
20
w || z;
10
!w;
false
7.4 赋值运算符:=, +=, -=, *=, /=
m = 1
1
m += 2
3
m -= 1
2
m *= 4
8
m /= 2;
4
8.流程控制
8.1 if-else
var a = 10;
undefined
if (a>5){
console.log('ok');
}else {
console.log('no');
}
VM2102:2 ok
undefined
8.2 if else-if
if (a>5){
console.log('a>5');
}else if (a<5){
console.log('a<5');
}else {
console.log('a=5');
}
VM2173:2 a>5
undefined
8.3 switch
var day = new Date().getDay();
switch (day) {
case 0:
console.log('Sunday');
break;
case 1:
console.log('Monday');
break;
case 2:
console.log('Tuesday');
break;
case 3:
console.log('Wednesday');
break;
case 4:
console.log('Thursday');
break;
case 5:
console.log('Friday');
break;
case 6:
console.log('Saturday');
break;
}
VM2176:19 Friday
//switch中的case语句通常都会加break语句,否则程序会继续执行后续case中的语句
var day = new Date().getDay();
switch (day) {
case 0:
console.log('Sunday');
break;
case 1:
console.log('Monday');
break;
case 2:
console.log('Tuesday');
break;
case 3:
console.log('Wednesday');
break;
case 4:
console.log('Thursday');
break;
case 5:
console.log('Friday');
case 6:
console.log('Saturday');
}
VM2216:19 Friday
VM2216:21 Saturday
8.4 for
for (var i=0;i<10;i++){
console.log(i);
}
VM2283:2 0
VM2283:2 1
VM2283:2 2
VM2283:2 3
VM2283:2 4
VM2283:2 5
VM2283:2 6
VM2283:2 7
VM2283:2 8
VM2283:2 9
undefined
8.5 while
var i = 0;
undefined
while (i<10){
console.log(i);
i++;
}
VM2361:2 0
VM2361:2 1
VM2361:2 2
VM2361:2 3
VM2361:2 4
VM2361:2 5
VM2361:2 6
VM2361:2 7
VM2361:2 8
VM2361:2 9
8.6 三元运算
var a = 1;
undefined
var b = 2;
undefined
var c = a>b?a:b;
undefined
c
2
//这里的三元运算顺序是先写判断条件a>b再写条件成立返回的值为a,条件不成立返回的值为b;三元运算可以嵌套使用;
var a = 10,b = 20;
undefined
var x =a>b?a:(b=='20')?a:b;
undefined
x
10
9.函数
9.1函数定义
JavaScript中的函数和Python中的非常类似,只是定义方式有点区别。
//普通函数定义
function f1(){
console.log('hello world')
}
//带参数函数
function f2(a,b){
console.log(arguments); //内置对象
console.log(arguments.length);
console.log(a,b);
}
//带返回值的函数
function sum(a,b){
return a+b;
}
sum(1,2); //调用函数
//匿名函数方式
var sum = function(a,b){
return a+b;
}
sum(1,2);
//立即执行函数,书写立即执行函数,首先先写两个括号,防止书写混乱
(function(a,b){
return a+b;
})(1,2);
补充:
ES6中允许使用箭头(=>)定义函数
var f = v => v;
//等同于
var f = function(v){
return v;
}
如果箭头函数不需要参数或需要多个参数,就用圆括号代表参数部分:
var f = () => 5;
//等同于
var f = function(){return 5};
var sum = (num1+num2) => num1 + num2;
//等同于
var sum = function(num1,num2){return num1+num2};
//这里的return只能返回一个值,如果想返回多个值需要自己手动给他们包一个数组或对象
9.2函数中的arguments参数
function add(a,b){
console.log(a+b);
console.log(arguments.length); //包含了传入的全部参数
console.log(arguments[0]); //取第一个传入的参数
}
undefined
add(1,2,3,4,5);
VM2961:2 3
VM2961:3 5
VM2961:4 1
undefined
9.3函数的全局变量和局部变量
局部变量:在JavaScript函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它(该变量的作用域是函数内部)。只要函数运行完毕,本地变量就会被删除。
全局变量:在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。
变量生存周期:
- JavaScript变量的生命期从它们被声明的时间开始
- 局部变量会在函数运行以后被删除
- 全局变量会在页面关闭后被删除
9.4作用域
首先在函数内部查找变量,找不到则到外层函数查找,逐步找到最外层,与python作用域一样
示例
var city = 'beijing';
undefined
function f(){
var city = 'shanghai';
function inner(){
var city = 'shenzhen';
console.log(city);
}
inner()
}
undefined
f()
VM3161:5 shenzhen
undefined
var city = 'beijing';
undefined
function bar(){
console.log(city);
}
undefined
function f(){
var city = 'shanghai';
return bar;
}
undefined
var res = f()
undefined
res()
VM3258:2 beijing
undefined
//闭包
var city = 'beijing';
function f(){
var city = 'shanghai';
function inner(){
console.log(city);
}
return inner;
}
var res = f();
res(); //打印结果是'shanghai',一层一层往上找
10.内置对象和方法
10.1自定义对象
JavaScript的对象(object)本质上是键值对的集合(Hash结构),但是只能用字符串作为键
var a = {'name':'lucas','age':18};
console.log(a.name);
console.log(a['age']);
遍历对象中的内容
var a = {'name':'lucas','age':18};
for (var i in a){
console.log(i,a[i]);
}
10.2 创建对象:
var person = new Object(); //创建一个person对象
person.name = 'lucas'; //person对象的name属性
person.age = 18; //person对象的age属性
注意:
ES6中提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当做键。
也就是说,Object结构提供了“字符串--值”的对应,Map结构提供了“值--值”的对应,是一种更完善的Hash结构实现
var m = new Map();
undefined
var o = {p:'content'}
undefined
m.set(o,'hello world')
Map(1) {{…} => "hello world"}
m.get(o)
"hello world"
m.has(o)
true
m.delete(o)
true
m.has(0)
false
10.3 Date对象
创建Date对象
//不指定参数
var d1 = new Date();
console.log(d1.toLocaleString());
//参数为日期字符串
var d2 = new Date("2004/3/20 11:12");
console.log(d2.toLocaleString());
VM3705:2 2004/3/20 上午11:12:00
undefined
var d3 = new Date("04/03/20 11:12");
console.log(d3.toLocaleString());
VM3708:2 2020/4/3 上午11:12:00
undefined
//参数为毫秒数
var d3 = new Date(5000);
console.log(d3.toLocaleString());
console.log(d3.toUTCString());
VM3711:2 1970/1/1 上午8:00:05
VM3711:3 Thu, 01 Jan 1970 00:00:05 GMT
undefined
//参数为年月日小时分钟秒毫秒
var d4 = new Date(2004,2,20,11,12,0,300);
console.log(d4.toLocaleString());
VM3714:2 2004/3/20 上午11:12:00 //毫秒并不显示
undefined
Date对象的方法:
var d = new Date();
//getDate() 获取日
//getDay () 获取星期
//getMonth () 获取月(0-11)
//getFullYear () 获取完整年份
//getYear () 获取年
//getHours () 获取小时
//getMinutes () 获取分钟
//getSeconds () 获取秒
//getMilliseconds () 获取毫秒
//getTime () 返回累计毫秒数(从1970/1/1午夜)
10.4 json对象
var str1 = '{"name": "Alex", "age": 18}';
undefined
var obj1 = {"name": "Alex", "age": 18};
undefined
var obj = JSON.parse(str1); //json.loads
undefined
var str = JSON.stringify(obj1); //json.dunps
undefined
obj
{name: "Alex", age: 18}
str
"{"name":"Alex","age":18}"
10.5 RegExp对象
//定义正则表达式两种方式
var reg1 = new RegExp('^[a-zA-Z][a-zA-Z0-9]{5,11}');
var reg2 = /^[a-zA-z][a-zA-Z0-9]{5,9}$/;
// 正则校验数据
reg1.test('lucas666')
reg2.test('lucas666')
/*第一个注意事项,正则表达式中不能有空格*/
// 全局匹配
var s1 = 'egondsb dsb dsb';
s1.match(/s/)
s1.match(/s/g)
var reg2 = /^[a-zA-Z][a-zA-Z0-9]{5,9}$/g
reg2.test('egondsb');
reg2.test('egondsb');
reg2.lastIndex;
/*第二个注意事项,全局匹配时有一个lastIndex属性*/
// 校验时不传参数
var reg2 = /^[a-zA-Z][a-zA-Z0-9]{5,9}$/
reg2.test();
reg2.test(undefined);
var reg3 = /undefined/;
reg3.test();