JavaScript


JavaScript 介绍

  • 完整的 JavaScript 实现是由以下 3 个不同部分组成的:
    • 核心(ECMAScript)
    • 文档对象模型(DOM) Document object model (整合js,css,html)
    • 浏览器对象模型(BOM) Broswer object model(整合js和浏览器)
  • Javascript 在开发中绝大多数情况是基于对象的.也是面向对象的.

ECMAScript

ECMAScript 是一个重要的标准,但它并不是 JavaScript 唯一的部分,
ECMAScript和JavaScript的关系是,前者是后者的规格,后者是前者的一种实现。
ES6就是指ECMAScript 6。

简单地说,ECMAScript 描述了以下内容:

  • 语法
  • 类型
  • 语句
  • 关键字
  • 保留字
  • 运算符
  • 对象 (封装 继承 多态) 基于对象的语言.使用对象.

JavaScript 概述

  • JavaScript是脚本语言, 将JS插入 HTML 页面后,可由所有的现代浏览器执行。
  • JS跑在浏览器上,他的解释器就是浏览器,有浏览器就能跑 JS。

JavaScript 基础

JS 引入方式

  • JS文件是在后端写的,浏览器通过网络从后端拿过来,然后在执行,如果找不到JS文件浏览器并不会报错
  1. 直接编写

    1
    2
    3
    <script>
    alert('hello')
    </script>
  2. 文件引入

    1
    <script src="jojo.js"></script>

JS 语言规范

注释

1
// 单行注释
1
/* 我是多行注释 */

结束符

  • js语句之间有分号(;)为结束符,python通过缩进

JS 语言基础

变量声明

  • js属于动态类型。(同一个变量可以存不同数据类型的值)
  • 声明变量使用 var 变量名; 的格式来进行声明。
  • 一行可以声明多个变量.并且可以是不同类型。
  • JavaScript的变量名可以使用_,数字,字母,$组成,不能以数字开头。
  • js中$也可以做变量名。
    1
    2
    var userName = 'leo';
    var userName = 'leo',age = 28,city="beijing";

  • 注意

    • 变量名是区分大小写的。
    • 推荐使用驼峰式命名规则。
      Camel 标记法
      首字母是小写的,接下来的字母都以大写字符开头。例如:
      var myTestValue = 0, mySecondValue = “hi”;
    • 保留字不能用做变量名。


      保留字列表
      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
      abstract
      boolean
      byte
      char
      class
      const
      debugger
      double
      enum
      export
      extends
      final
      float
      goto
      implements
      import
      int
      interface
      long
      native
      package
      private
      protected
      public
      short
      static
      super
      synchronized
      throws
      transient
      volatile


JS 数据类型

JS 动态类型

  • JS属于动态类型语言
    • 动态类型:声明变量即可以是字符串也可以是数字
    • 静态类型,在声明变量的时候,声明类型,严谨,执行效率快,不用判断变量,范围缩小
1
2
3
4
5
6
7
8
9
10
11
var x  
typeof(x)
"undefined"

var name = "leo"
typeof(name)
"string"

var age = 28
typeof(age)
"number"

数值(Number)

  • JavaScript不区分整型和浮点型,就只有一种数字类型。
1
2
3
4
5
6
7
8
9
10
var n1 = 28
var n2 = 28.00
var n3 = NaN ### NaN,表示不是一个数字(Not a Number)。

typeof(n1)
"number"
typeof(n2)
"number"
typeof(n3)
"number"
1
2
3
var name = 'leo'
parseInt(name) ### 表示强转后,结果并不是一个数字
NaN

字符串(String)

  • 字符串拼接用 + 号
1
2
3
4
5
var s1 = "jojo"
var s2 = "bobo"
var s3 = s1+s2
console.log(s3)
### jojobobo
  • 字符串的常用方法

布尔值(Boolean)

  • 区别于Python,true和false都是小写。
  • “”(空字符串)、0、null、undefined、NaN都是false
1
2
var a = true;
var b = false;

null和undefined

  • null表示值是空,一般在需要指定或清空一个变量时才会使用,如 name=null;
  • undefined表示当声明一个变量但未初始化时,该变量的默认值是undefined。
  • 函数无明确的返回值时,返回的也是undefined。
  • null表示变量的值是空,undefined则表示只声明了变量,但还没有赋值。
1
2
3
null == undefined
弱等于 10 == "10"
强等于 10 === "10"
1
2
3
4
5
6
7
var age

age
undefined

typeof age
"undefined"

对象(Object)

  • JavaScript 中的所有事物都是对象:字符串、数值、数组、函数…此外,JavaScript 允许自定义对象。
  • JavaScript 提供多个内建对象,比如 String、Date、Array 等等。
  • 对象只是带有属性和方法的特殊数据类型。

数组:

  • 数组对象的作用是:使用单独的变量名来存储一系列的值。类似于Python中的列表。
1
2
var l1 = ['a','b','c','d','e']
console.log(l1[1])

常用方法:

遍历数组中的元素:

1
2
3
4
5
6
7
8
for (var i=0;i<l1.length;i++){
console.log(i)
}
0
1
2
3
4

字典对象:

1
2
3
4
5
6
7
8
9
10
11
var person = {
name : 'leo',
age : 18
};
undefined
person.name
"leo"
person.age
18
person
{name: "leo", age: 18}

运算符

算数运算符

+ - * / % ++ --

比较运算符

> >= < <= != == === !==

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
10 == '10'
true ### 弱等于
10 === '10'
false ### 强等于,既判断类型又判断值 ,一般使用强等于


null == undefined
true
null === undefined
false

typeof null
"object"
typeof undefined
"undefined"

逻辑运算符

&& || !

1
与and 或or 非!

赋值运算符

= += -= *= /=

1
2
3
4
5
6
7
var n = 1
n = 2
2
n += 2
4
n -= 1
3

流程控制

if-else if-else

1
2
3
4
5
6
7
8
var a = 5;
if (a > 5){
console.log(" a > 5");
}else if (a < 5){
console.log(" a < 5");
}else{
console.log(" a = 5");
}

switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 获取今天周几
var day = new Date().getDay();

switch (day){
case 0:
console.log("Sunday");
break;
case 1:
console.log("Monday");
break;
default:
console.log("...")
}
Monday
  • switch中的case子句通常都会加break语句,否则程序会继续执行后续case中的语句。

for

1
2
3
4
5
6
7
8
9
10
11
var l1 = [1,2,'leo']
for (var i = 0;i < l1.length;i++){
console.log(i) // 索引
console.log(l1[i]) // 值
}
0
1
1
2
2
leo

while

1
2
3
4
5
6
// 循环要有一个准确的终止条件
var age = 10;
while (age < 18){
console.log("可以进入");
age += 1
}

三元运算

1
2
3
4
5
6
### python
a = 10
b = 5
c = a if a > b else b
print(c)
10
1
2
3
4
5
6
// js
var a = 10;
var b = 20;

var c = a > b ? a:b
// 问号 ? 前面是条件,后面是取值,成立取a,不成立取b(冒号后面的值)

函数

函数定义

1
2
3
4
5
6
7
8
9
// 普通函数 带参函数
function func(a,b) {
console.log(a);
console.log(b);
return a + b // 返回值
}

ret = func(10,20) // 函数执行 接收返回值
console.log('a + b = ' + ret)
1
2
3
4
5
6
7
8
9
// 匿名函数 没有函数名,存在变量里
var func2 = function (a,b) {
console.log(a);
console.log(b);
return a + b
}

ret = func2(10,20)
console.log('a + b = ' + ret)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 参数个数
function func(a,b) {
console.log(a);
console.log(b);
return a + b
}

// ret = func(10,20,30)
// 多一个参数传进来 并不会报错 继续执行

ret = func(10)
// 少一个参数传进来 b = undefined , a + b = NaN
// 也就是说b被声明了,但是没有赋值,相加的结果是NAN

console.log('a + b = ' + ret)
1
2
3
4
5
// 立即执行函数
(function (a,b) {
console.log('立即执行函数')
console.log(a+b)
})(10,20);

arguments 参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// arguments参数 有点像 python中的args 他可以用来接收多个参数
// arguments 找到所有传进的参数 == *args

function func(a,b) {
console.log(arguments);
console.log('参数个数:' + arguments.length);
var ret = 0;
for (var i = 0;i<arguments.length;i++){
ret += arguments[i]
}
return ret // 3个参数相加之和
}

ret = func(10,20,30)
console.log(ret)

// Arguments(3) [10, 20, 30, callee: ƒ, Symbol(Symbol.iterator): ƒ]
// 参数个数:3
// 60

函数的全局变量和局部变量

局部变量:

1
2
1. 在JavaScript函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它(该变量的作用域是函数内部)。
2. 只要函数运行完毕,本地变量就会被删除。

全局变量:

1
1. 在函数外声明的变量是全局变量,网页上的所有脚本和函数都能访问它。

变量生存周期:

1
2
3
1. JavaScript变量的生命期从它们被声明的时间开始。
2. 局部变量会在函数运行以后被删除。
3. 全局变量会在页面关闭后被删除。

作用域

变量的查找顺序:

1
2
1. 函数的调用,要往回找,找到函数的定义阶段
2. 变量首先在 函数的内部找 -> 内部找不到就往外找 -> 直到找到全局为止,全局都没有就是undefined。

1
2
3
4
5
6
7
8
9
10
var city = "BeiJing";
function f() {
var city = "ShangHai";
function inner(){
var city = "ShenZhen";
console.log(city);
}
inner();
}
f(); //输出结果是? ShenZhen
1
2
3
4
5
6
7
8
9
10
var city = "BeiJing";
function Bar() {
console.log(city);
}
function f() {
var city = "ShangHai";
return Bar;
}
var ret = f();
ret(); // 打印结果是? BeiJing

1
2
3
4
5
6
7
8
9
10
11
// 闭包
var city = "BeiJing";
function f(){
var city = "ShangHai";
function inner(){
console.log(city);
}
return inner;
}
var ret = f();
ret(); // ShangHai

词法分析(尝试理解)

1
2
3
4
5
1.分析(函数内部变量的定义过程)
1.先看参数
2.看有没有局部变量
3.看有没有函数定义
2.执行(实际执行代码)

JavaScript中在调用函数的那一瞬间,会先进行词法分析。

  • 当函数 调用 的前一瞬间,会先形成一个激活对象:Avtive Object(AO),并会分析以下3个方面:
1
2
3
1:函数参数,如果有,则将此参数赋值给AO,且值为undefined。如果没有,则不做任何操作。
2:函数局部变量,如果AO上有同名的值,则不做任何操作。如果没有,则将此变量赋值给AO,并且值为undefined。
3:函数声明,如果AO上有,则会将AO上的对象覆盖。如果没有,则不做任何操作。

函数内部无论是使用参数还是使用局部变量都到AO上找。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var age = 18;
function foo(){
console.log(age);
var age = 22;
console.log(age);
}
foo(); // 问:执行foo()之后的结果是?

// 分析:
// 1.函数没有参数
// 2.有局部变量 age 那么 ao.age = undefined
// 3.有变量赋值 age = 22
// 第一个age = undefined
// 第二个age = 22

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var age = 18;
function foo(){
console.log(age);
var age = 22;
console.log(age);
function age(){
console.log("呵呵");
}
console.log(age);
}
foo(); // 执行后的结果是?

// 分析:
// 1 没有参数
// 2.age = undefined
// 3.age = 22
// 4.function age = ao.age = function age()...

// 1. function age()...
// 2. 22
// 3 .22 同理第三个输出的还是22, 因为中间再没有改变age值的语句了

内置对象和方法

对象的属性

  • JavaScript中的所有事物都是对象:字符串、数字、数组、日期,等等。

1
2
3
4
5
6
7
8
9
// 字符串对象创建
// var 变量 = “字符串”
// var 字串对象名称 = new String (字符串)
var name1 = "leo"
var name2 = new String("Leo")
typeof name1
"string"
typeof name2
"object"
1
2
3
4
5
6
7
// 数组对象创建
var l1 = [1,2,3]
var l2 = new Array(1,2,3)
l1
(3) [1, 2, 3]
l2
(3) [1, 2, 3]
1
2
3
4
5
6
7
8
9
10
11
12
// 数字类型对象创建
var n1 = 28
n1
28
var n2 = new Number(30)
n2
Number {30}

typeof n1
"number"
typeof n2
"object"

自定义对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 第一种方法 直接创建
// 自定义对象
var person = {
"name":"leo",
"age":28
}

console.log(person)
console.log(typeof person)
console.log(person.name)
console.log(person.age)

// 循环遍历对象属性
for (var i in person){
console.log(i) // 键
console.log(person[i]) // 值
}

// 注意:
// 1. 键不用加引号,加上也不出错 {name:"leo",age:28}
// 2. 值如果是字符串,必须写双引号
1
2
3
4
5
6
7
8
// 第二种方法  new 关键字创建
var person = new Object()
person.name = "leo"
person.age = 28
person.city = "北京"
console.log(person.name + person.age)
var index3 = 'city' // 刚巧我有一个变量的值是对象里面的键
console.log(person[index3]) // 变量取值

内置对象

Date对象

  • 内置对象相当于python当中的内置模块
1
2
3
4
5
6
7
// 创建Date对象
// Date对象
var d1 = new Date();
console.log(d1); // Tue Jun 11 2019 18:04:34 GMT+0800 (中国标准时间)
console.log(typeof d1); // object
console.log(d1.toLocaleString()); // 2019/6/11 下午6:04:34 字符串时间
console.log(typeof d1.toLocaleString()); // string
1
2
3
4
5
6
7
// 生成指定时间的date对象
var d2 = new Date("2019/06/11 18:10");
var d3 = new Date("2019-06-11 18:10");
var d4 = new Date("2019/06/11 18:10");
console.log(d2.toLocaleString()); // 转成字符串格式的 本地时间 2019/6/11 下午6:10:00
console.log(d3.toLocaleString()); // 2019/6/11 下午6:10:00
console.log(d4.toUTCString()); // Tue, 11 Jun 2019 10:10:00 GMT UTC时间
1
2
3
4
5
6
7
8
9
10
11
// Date对象的方法
var d = new Date();
console.log(d.getDate()); //获取日
console.log(d.getDay ()); //获取星期
console.log(d.getMonth ()); //获取月(0-11)
console.log(d.getFullYear ()); //获取完整年份
console.log(d.getHours ()); //获取小时
console.log(d.getMinutes ()); //获取分钟
console.log(d.getSeconds ()); //获取秒
console.log(d.getMilliseconds ()); //获取毫秒
console.log(d.getTime ()); //返回累计毫秒数(从1970/1/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
// 编写代码,将当前日期按“2017-12-27 11:11 星期三”格式输出。

var weekday = {
"0":"星期日",
"1":"星期一",
"2":"星期二",
"3":"星期三",
"4":"星期四",
"5":"星期五",
"6":"星期六"
}

function get_day() {
var d = new Date()
var year = d.getFullYear()
var month = d.getMonth()+1; // 月份是0-11 所以加1
var day = d.getDay();
var h = d.getHours();
var m = d.getMinutes() < 10 ? "0" + d.getMinutes():d.getMinutes(); // 三元运算 如果分钟<10 在前面加个0
var week_day = weekday[d.getDay()]
var strTime = `${year}-${month}-${day} ${h}:${m} ${week_day}`;
console.log(strTime)
}
get_day()

JSON对象

1
2
3
4
5
6
7
8
9
10
// 字符串转成对象
var person = '{"name":"leo","age":28}' // 字符串
var json_s = JSON.parse(person)
console.log(json_s)
console.log(typeof json_s) // object

// 对象转换成字符串
var ob_s = JSON.stringify(json_s)
console.log(ob_s)
console.log(typeof ob_s) // string

Math对象

  • 同样Math用于数据科学计算
1
2
3
4
5
6
7
8
9
10
11
12
abs(x);      //返回数的绝对值。
exp(x); //返回 e 的指数。
floor(x); //对数进行下舍入。
log(x); //返回数的自然对数(底为e)。
max(x,y); //返回 x 和 y 中的最高值。
min(x,y); //返回 x 和 y 中的最低值。
pow(x,y); //返回 x 的 y 次幂。
random(); //返回 0 ~ 1 之间的随机数。
round(x); //把数四舍五入为最接近的整数。
sin(x); //返回数的正弦。
sqrt(x); //返回数的平方根。
tan(x); //返回角的正切。
1
2
var n = -100
console.log(Math.abs(n))

RegExp对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 创建正则对象方式1
// 参数1 正则表达式(不能有空格)
// 参数2 匹配模式:常用g(全局匹配;找到所有匹配,而不是在第一个匹配后停止)和i(忽略大小写)

// 例子:用户名,只能是英文字母、数字和_,并且首字母必须是英文字母。长度最短不能少于6位 最长不能超过12位。
// ^[a-zA-Z][a-zA-Z0-9_]{5,12}

// 创建RegExp对象方式(逗号后面不要加空格)
var reg1 = new RegExp("^[a-zA-Z][a-zA-Z0-9_]{5,12}$");
var str1 = "abcde" // 待匹配字符串: 5位字符组成
var str2 = "abcdef" // 待匹配字符串: 6位字符组成
var str3 = "1abcdef" // 待匹配字符串: 7位字符组成,数字开头
//RegExp对象的test方法,测试一个字符串是否符合对应的正则规则,返回值是true或false。
console.log(reg1.test(str1)) // false 开头占1位,后面如果是4个字符,满足不了 {5,12}
console.log(reg1.test(str2)) // true 1+5
console.log(reg1.test(str3)) // false 不能数字开头
1
2
3
4
5
6
7
// 第二种写法 /正则/
// 创建方式2
// /填写正则表达式/匹配模式(逗号后面不要加空格)=

var reg2 = /^[a-zA-Z][a-zA-Z0-9_]{5,12}$/;
var str2 = 'abcdef'
console.log(reg2.test(str2))
1
2
3
4
5
6
7
// String对象与正则结合的4个方法
var s2 = "hello world";

s2.match(/o/g); // ["o", "o"] 查找字符串中 符合正则 的内容
s2.search(/h/g); // 0 查找字符串中符合正则表达式的内容位置
s2.split(/o/g); // ["hell", " w", "rld"] 按照正则表达式对字符串进行切割
s2.replace(/o/g, "s"); // "hells wsrld" 对字符串按照正则进行替换
1
2
3
4
// 坑1
console.log("==============================================================")
// 正则表达式之间 不能有空格 {5, 11} 要不然就被崩
//console.log(/^[a-zA-Z][a-zA-Z0-9]{5, 11}$/.test('xiaoqiang'))
1
2
3
4
5
6
7
8
// 坑2
// test 不传值 相当于传了一个 undefined
// test() 就把undefined 当成是 "undefined" 来判断
console.log("==============================================================")
console.log(/^[a-zA-Z][a-zA-Z0-9]{5,11}$/.test())
console.log(/^[0-9a-zA-Z][a-zA-Z0-9]{5,11}$/.test())
console.log(/^[0-9a-zA-Z][a-zA-Z0-9]{5,11}$/.test(undefined))
console.log(/^[0-9][a-zA-Z0-9]{5,11}$/.test())
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
// 字符串替换 不是改变原来的字符串,需要生成新的字符串
var ss = 'Leo'
var s3 = ss.replace("o","x")
console.log(s3)

// 正则 全部替换g 忽略大小写i
// JS正则的两种模式:
// 1. g 表示全局
// 2. i 忽略大小写
var ss = 'AbAcad'
var s4 = ss.replace(/A/gi,"哈哈哈")
console.log(s4)

// 坑3
// 当正则表达式使用了全局模式(g)时,并且你还让他去检测一个字符串
// 此时会引出 lastIndex 记录上次匹配成功位置,并把下一次要开始效验的位置记住
// 所以一般不要设置全局

// a开头后面2-4位字符
// console.log(/^a[a-zA-Z]{2,4}$/g.test("alex"))
// console.log(/^a[a-zA-Z]{2,4}$/g.test("alex"))

var r = /alex/g;
console.log(r.test("alex")) // ture
console.log(r.lastIndex) // 4
console.log(r.test("alex")) // false 从头开始
console.log(r.lastIndex) // 0