JavaScript

"""
JavaScript(JS)是脚本编程语言,JS语言开发的文件是以.js为后缀,通过在html文件中引入该js文件来控制html代码的交互功能以及前台数据处理的业务逻辑(js语言代码也可以直接写在html文件中),采用的ECMAScript语法,属于编程语言。

ECMAScript目前普遍使用的存在ES5与ES6两个版本,我们也会基于这两个版本来介绍JS这么应用的学习
ES5:基于对象语言(没有class),通常学的多。
ES6:面向对象语言,有新特性,新框架。
"""

"""
学习方向:从JS代码书写位置、JS基础语法、JS选择器和JS页面操作四部分进行学习

学习目的:完成页面标签与用户的人机交互及前台数据处理的业务逻辑
"""

脚本语言

脚本语言:通过这门语言,可以去写一些代码片段,这些代码片段可以嵌入到其他语言中,只要给予一个执行的入口,就可以执行代码。如c,java,这些语言必须要有明确的入口,也就是main函数,从main函数入,从main函数出。python则处处是入口处处是出口,没有所谓的main函数,这就是脚本语言的特点,也就是说只要给一个执行的入口,我就能够让代码跑起来。

脚本:像python可以直接用解释器运行,不管文件中有没有main函数,甚至是空的,也可以跑起来,只是没结果,也就是说可以通过代码块来执行,那么我就可以把这些代码块嵌入到其他语言中,这就是脚本。如果利用了其他语言的bug,那么就成了外挂。如果把程序中一些不好的点,补齐了,那么就成了补丁。

脚本语言就可以用来给其他东西拓展功能。如javascript就可以用来给网页拓展功能

项目重构(代码重构)

为了节约开发成本,或者对数据进行一些更高层次的维护,就会往程序中加入一些脚本。而一种语言编写的程序,功能开始慢慢的向另一种语言上迁移。直到彻底迁移完成,这个过程就叫项目重构。换语言,最大的目的就是提高效率,如果一次性修改,会带来巨大的损失,所以在这种把损失降低到最小的基础上,进行代码的功能迁移。

js的引入方式

钩子事件:提前写一个代码块,设置了一个激活条件(相当于放了一个钩子),一旦条件达到,方法就会被调用,满足条件才会激活的方法就叫钩子。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>引入</title>
    <style>
        #box {
             200px;
            height: 200px;
            background-color: orange;
        }
        /*#box:active {*/
            /*background-color: red;*/
        /*}*/
    </style>

</head>
<body>
    <!--行间式:js代码直接书写在标签的钩子事件中-->
    <!--<div id="box" onclick="this.style.backgroundColor = 'red'"></div>-->
    <div id="box"></div>

</body>
<!--内联式:js代码书写在script标签中,script需要放置在body的最下方-->
<!--<script>-->
    <!--box.style.backgroundColor = 'pink'-->
<!--</script>-->
<script src="js/外联.js">
    // 链接了外部js的script标签,就相当于单标签,内部代码块会自动屏蔽
    box.style.borderRadius = '50%'
</script>
</html>
js/外联.js
box.style.background = 'blue'

js的基础语法

变量

没有解压缩

// 关键字 变量名 = 变量值
// 关键字四种:不写 | var | let | const
n1 = 10;  // 全局变量
// console.log(n1);
var n2 = 20;  // 局部变量
// alert(n2);
let n3 = 30;  // 块级变量
// document.write(n3);
const N4 = 40;  // 常量
// console.log(N4);
// N4 = 50;  // 报错,常量值不能修改

数据类型

// 值类型
// 1) 数字类型:number
var num1 = 10;
var num2 = 3.14;
console.log(num1, num2);
console.log(typeof(num1), typeof num2);

// 2) 字符串类型:string
var s1 = '单引号的字符串';
var s2 = "双引号的字符串";
console.log(s1, s2);
console.log(typeof s1, typeof s2);
var s3 = `多行字符串:
再来一行`;
console.log(typeof s3, s3);

// 3) 布尔类型:boolean
var b1 = true;
var b2 = false;
console.log(b1, b2);
console.log(typeof b1, typeof b2);
// console.log(true + true);  // 1+1
	
// 4) 未定义类型:undefined
// 不报错是因为python中直接与内存交互,而js是和页面交互,而页面会给予一个undefined这个值
var owen;
console.log(owen);
var nick = undefined;
console.log(nick);

// 引用类型
// 5) 对象类型
var obj = new Object();
console.log(typeof obj, obj);
var obj2 = {};
console.log(typeof obj2, obj2);

// 6) 函数类型
var fn = function () {};
console.log(typeof fn, fn);

// 其它
// 7) 空类型
var jerry = null;
console.log(typeof jerry, jerry);

// 8) 数组
var arr = [1, 3, 2, 5, 4];
console.log(typeof arr, arr);

// 9) 时间
var date = new Date();
console.log(typeof date, date);

随机数

// 随机数: Math.random() - (0, 1)
// console.log(Math.random());

// 正整数区间[m, n]
// parseInt:向下取整
// (0, 1) * 10 => (0, 10) 取值parseInt() => [0, 9] + 5 => [5, 14]
// parseInt(Math.random() * 11) + 5 => [5, 15]
// [m, n] => +的值就是m,*的值 n - m + 1

// parseInt(Math.random() * (n - m + 1)) + m => [m, n]
var r_num = parseInt(Math.random() * (14 - 7 + 1)) + 7;
console.log(r_num);

// (0, 1) * 超大的数 取整
// 一个正整数 % num => [0, num-1] + m => [m, num-1+m] => n = num+m-1 => num = n-m+1
// 一个正整数 % (n-m+1) + m => [m, n]
var random_num = parseInt( Math.random() * 10000000000 % (14 - 7 + 1) ) + 7;
console.log(random_num)

运算符:详情见课件

​ 弱语言类型:允许将一块内存看做多种类型。比如直接将整型变量与字符变量相加。c、c++、php、js等都是若语言类型。

​ 强语言类型:在没有强制类型转化前,不允许两种不同类型的变量相互操作。Java、C# 和 Python 等都是强类型语言。

NaN:not a number 不是一个数字,一般出现在数字类型和一些无法进行计算的数据进行计算时,得到的结果就是NaN

// 1)算术运算符:+ - * / % ++ -- | += ...
console.log(5 / 2);  // 2.5
console.log(parseInt(5 / 2));	// 地板除取整 2
console.log(parseFloat(5 / 2));	// 2.5

// parseInt | parseFloat 可以完成 string => number
res = parseInt('3.14.15abc');
console.log(res);  // 从头往后找整数部分

res = parseFloat('3.14.15abc');
console.log(res);  // 从头往后找小数部分(最多只识别一个小数点)

res = parseInt('a3.14.15abc');  
console.log(typeof res, res);	// number, NaN

// 2) 弱语言类型的js
res = 10 + '5';
console.log(res);  // 字符串:105
res = 10 - '5';
console.log(res);  // 数字:5
// 数字 => 字符串
res = '' + 5;
console.log(typeof res, res);
// 字符串 => 数字
res = +'5';		// '5' - 0 也是可以的
console.log(typeof res, res);

// 3) 自增自减
num = 10;
num += 1;
console.log(num);
num++;
console.log(num);
num--;
console.log(num);
// 了解:符号 在前优先级高于一切运算符,在后优先级比赋值符还低
// ++在前先自增再运算;++在后先运算再自增,意义不大,想要调整优先级就用括号
num = 10;
res = num++;
console.log(num, res);

num = 10;
res = ++num;
console.log(num, res);

// 4) 比较运算符的比较
console.log(5 == '5');  // true,只做值比较
console.log(5 === '5');  // false,做值与类型比较
console.log(5 != '5');  // false,只做值比较
console.log(5 !== '5');  // true,做值与类型比较

// 5)逻辑运算符 && || !
console.log(true && true);
console.log(false || false);
console.log(!true);
// 短路现象
// &&: 有假则假,前为假,后不用判断
// ||: 有真则真,前为真,后不用判断
num = 10;
console.log(false && ++num);  // num++ | ++num 都被短路不会被执行
console.log(num);

console.log(true || ++num);  // num++ | ++num 都被短路不会被执行
console.log(num);

// 6)三元运算符(三目运算符)
// 条件 ? 结果1 : 结果2
res = 5 == '5' ? '值相等':'值不等';
console.log(res);

分支结构

// 1)if分支结构
/* python
    * if 条件:
    *   代码块1
    * elif 条件:
    *   代码块2
    * else:
    *   代码块3
    * */
/** js
     * if (条件) {
     *     代码块1
     * }
     * else if (条件) {
     *     代码块2
     * }
     * else {
     *     代码块3
     * }
     */
var num = parseInt(Math.random() * 16);
console.log(num);
if (num > 10) {
    console.log("产生的数超过10")
} else if (5 <= num && num <= 10) {
    console.log("产生的数间于5~10")
} else {
    console.log("产生的数不超过5")
}

// 2)switch分支结构
/* 只会走case或者default,不会走普通的代码
    month = parseInt(Math.random() * (2 - 0 + 1)) + 0;
    console.log(month);
    switch (month) {
        case 1:
            console.log('1月31天');
            break;  // 用来结束case,跳出switch分支结构
        case 2:
            console.log('2月28天');
            break;
        default:  // 没有走任何case,会进入default分支
            console.log('月份参数有误');
    }
    */
month = parseInt(Math.random() * (12 - 1 + 1)) + 1;
console.log(month);
switch (month) {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        console.log('%s月31天', month);
        break;  // 用来结束case,跳出switch分支结构,多个分支可以共享一个break
    case 2:
        console.log('2月28天');
        break;
    case 4:
    case 6:
    case 9:
    case 11:
        console.log('%s月30天', month);
        break;
    default:    // 没有走任何case,会进入default分支,没有错误的情况可以省略
        console.log('月份参数有误');
}

循环结构

如果死循环,页面就会卡住

// 1) for循环
/*
    for (循环变量①; 条件表达式②; 增量③) { 循环体④ }

    生命周期:① ②④③...②④③ ②
     */
// 1~10之间的偶数
for (var i = 1; i <= 10; i++) {
    if (i % 2 === 0) {
        console.log(i);
    }
}
// 定义变量可以写在外面,增量可以写在里面
var i = 1;
for (i; i <= 10; ) {
    if (i % 2 === 0) {
        console.log(i);
    }
    i++;
}


// continue | break
// 输出1 2 4 5
for (var i = 1; i <= 5; i++) {
    if (i === 3) continue;	// if只有一条语句,可以省略大括号
    console.log(i)
}
// 输出1 2 3
for (var i = 1; i <= 5; i++) {
    if (i > 3) break;
    console.log(i)
}

// 2)while循环
var i = 1;
while (i <= 5) {
    console.log(i);
    i++;
}

// 3)do...while循环:先执行一次循环体,再判断条件
var num = 90;
do {
    console.log(num);
    num++;
} while (num <= 100);

// for:解决知道循环次数的循环

// while:
//      解决一切for与do...while能解决的问题(结合函数的思想)
//      解决不知道循环次数的循环(循环用break结合)

// do...while:完成循环体必须要提前执行一次的循环

函数

函数概况
/* 函数
    定义:
    关键字 函数名(参数列表) {
        函数体;
        返回值
    }
    var 函数名 = 关键字(参数列表) {
        函数体;
        返回值
    }
    var 函数名 = (参数列表) => {
        函数体;
        返回值
    }

    函数成员:
    函数名:存放函数的地址
            通过 函数名() 调用函数

    参数列表:将外界资源传给内部的桥梁
            你传你的,我收我的,用...接收可变长

    函数体:功能代码块

    返回值:将内部数据反馈给外部
            只能返回一个值,不写或空return返回undefined,写多个只会返回最后一个


    匿名函数:
    没有声明名字的函数
            产生一个局部作用域
            资源回收快
     */
有名函数
// 定义
function add(n1, n2) {
    return n1 + n2
}
// 使用
res = add(10, 20);
console.log(res);

// 函数名的运用
my_add = add;
console.log(my_add(100, 200));

// 参数列表:你传你的,我收我的,用...接收可变长
// 少传未接收到的形参赋值为undefined,多传的实参自动被丢弃
function fn(n1, n2) {
    console.log('传输的n1:%s | n2:%s', n1, n2)
}
fn(10, 20);
fn();
fn(100);
fn(1000, 2000, 3000);

// 可变长参数
function func(...num) {
    console.log(num)
}
func(1, 2, 5, 3, 4);
匿名函数
// 匿名函数
// 匿名函数的自调用 - 调用一次后就会被回收资源
// 放不了参数
(function () {
    console.log('匿名函数')
})();

// 用变量接收 - 函数的第二种声明方式
var fun = function () {
    console.log('函数的第二种声明方式')
};
fun();

// 函数的第三种声明方式
var fun2 = (n1, n2) => {  // 有函数体标明{}
    console.log('n1:%s | n2:%s', n1, n2);
    return n1 + n2
};
console.log(fun2(222, 444));

var fun3 = (n1, n2) => n1 + n2;  // 只有返回值可以省略{}
console.log(fun3(222, 444));

//js补充分号,但不会在括号中间加分号
匿名函数的局部作用域作用
// 匿名函数自调用,可以产生局部作用域与外界隔离
(function () {
    let number = 888
})();
// console.log(number)  // 外界不可以直接访问

四种变量分析

function fn() {
    n1 = 10; // 只有全局变量外界才能访问
    var n2 = 20;
    let n3 = 30;
    const n4 = 40;
}
fn();
console.log(n1);

if (true) {  // 块级作用域
    n1 = 10;
    var n2 = 20;
    let n3 = 30;  // let与const声明的变量有块级作用域
    const n4 = 40;  // 常量
}
console.log(n1);
console.log(n2);
{
    let aaa = 10
    }
// 同一块级,let关键字定义的变量名不能重复,否则会报错

数据类型的使用

字符串

// string => str
// 1)声明
// 单引号 | 双引号 | 反引号

// 2)字符串拼接
res = 'you are' + ' ' + 'good man!';
console.log(res);

// 3)字符串的切片
s = 'you are good man!';
n_s = s.slice(8, 12);
console.log(n_s);  // good

// 4)字符串替换
s = 'you are good man!';
n_s = s.replace('man', 'woman');
console.log(n_s);

// 5)字符串拆分
s = 'you are good man!';
res = s.split(' ');
console.log(res);

// 6)字符串迭代
s = 'abcdef';
for (num of s) {
    console.log(num)
}

数组

既有返回值,又会改变原列表

// array => list
// 1)声明
arr = [1, 4, 2, 3, 5];
console.log(arr);
// 2)反转
arr.reverse();
console.log(arr);
// 3)组合
str = arr.join('@');
console.log(str);
// 4)切片
new_arr = arr.slice(1, 4);
console.log(new_arr);
// 5)排序
arr.sort();
console.log(arr);
// 6)增删改查
// 查:只有正向索引
console.log(arr[2]);
// 增
arr.push(888);  // 尾增
console.log(arr);
arr.unshift(666);  // 首增
console.log(arr);
// 删
res = arr.pop();  // 尾删
console.log(arr, res);
res = arr.shift();  // 首删
console.log(arr, res);

// 增删改 综合方法:splice
// 万能方法,学了这个上面无视
// 三个参数:开始操作的索引 操作的位数 操作的结果(可变长)
arr = [1, 2, 3, 4, 5];
// 操作的位数为0,就是添加
// 操作的结果为空,就是删除
// 数组长度:arr.length
arr.splice(arr.length, 0, 666, 888);
console.log(arr);

字典

// object => dict
// 1)定义
height = 180;
dic = {
    'name': 'Owen',  // 本质是对象
    age: 18,  // 所有的key(属性名)都是字符串类型,所以可以省略引号
    height,  // 当value为变量,且变量名与key同名,可以省略value
};
console.log(dic);

// 2)访问
console.log(dic.name);
console.log(dic['age']);

// 3)增删改
// 增
dic.sex = '男';
console.log(dic);
// 删
delete dic.sex;
console.log(dic);
// 改
dic.name = 'Nick';
console.log(dic);