一、前言
1.JavaScript是脚本编程语言,也可以说是一种运行在浏览器中的解释型语言,js语言开发的文件是以.js为后缀的
2.JavaScript作用:通过在HTML文件中引入js文件来控制HTML代码的交互功能以及前台数据处理的业务逻辑,js语言也可以直接写在HTML文件中
3.JavaScript采用的是ECMAScript语法,ECMAScript目前普遍使用的版本有ES5和ES6两个版本,我们的学习也是基于这两个版本来完成的
4.学习方向:js代码书写位置(引入位置)、js基础语法(变量、数据类型、运算符、流程控制、函数、数据类型的使用)、js选择器和js页面操作四个大的方向
5.学习目的:完成页面标签与用户的人机交互以及前台数据处理的业务逻辑
二、js的引入方式
1.行间式(内嵌式)
1.语法:
<标签 on+事件类型="js代码" ></标签>
<!-- 例子 -->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>行间式</title>
<style>
#box {
300px;
height: 300px;
background-color: blue;
}
</style>
</head>
<body>
<!-- 必须要注意的是:“-”命名的方法必须将它省略并将连接的第一个字母大写-->
<div id="box" onclick="this.style.backgroundColor='red'">
点击就会变红
</div>
</body>
</html>
2.js代码直接书写在标签的钩子事件中
3.行间式引入方式必须结合事件来使用,内联式和外联式可以不结合事件
2.内联式
1.在head或body中,定义script标签,然后在script标签中书写js代码
2.需要注意的是:由于HTML和js都是脚本语言,都是书写一行执行一行,所以推荐将script标签以及js代码放在body标签最下方
<!-- 例子 -->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>内联式</title>
<style>
#box {
300px;
height: 300px;
background-color: blue;
}
</style>
</head>
<body>
<!-- 用于没有使用事件,所以会直接执行js代码-->
<div id = "box">
直接变粉
</div>
</body>
<script>
//必须将方法中的“-”及其后面的第一个字母一起换成该字母大写形式
box.style.backgroundColor = "pink"
</script>
</html>
3.外联式
1.先在.js文件中写好js代码,然后在HTML文件中通过script标签引入,直接在script标签内的src属性中链接js文件
2.链接外部js文件的script标签就相当于单标签,标签内的代码块会自动屏蔽
3.因此,外联式和内联式不要混在一个script标签中使用
//外联式.js
bax.style.background = 'yello'
<!-- 外联式.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>内联式</title>
<style>
#box {
300px;
height: 300px;
background-color: blue;
}
</style>
</head>
<body>
<!-- 用于没有使用事件,所以会直接执行js代码-->
<div id = "box">
直接变粉
</div>
</body>
<script src='外联式.js'></script>
</html>
三、js基础语法
1.变量
//语法:
//关键字 变量名 = 变量值
//关键字:不写/var/let/const
var a = 1;
1.1 全局变量
1.定义全局变量时,在变量名前面,什么都不用加,只需要给它赋值即可;或者是在除函数外的任何位置使用var声明的变量也是全局变量
2.全局变量可以在页面中任何位置被访问
3.如果页面不关闭,全局变量所占用的内存就不会释放,它会一直占用内存空间,直到页面关闭
4.全局变量可以重定义,变量名前不加任何关键字的声明方式不推荐使用
<script>
//隐式全局变量
a = 2
console.log(a)
//推荐使用的定义方式
var b = 3
console.log(b)
</script>
1.2 局部变量
1.局部变量,就是在函数内部用var声明的变量
2.局部变量在函数内定义和使用,它无法被函数外部所访问
3.用var声明的局部变量可以重定义
<script>
function f(n1, n2){
var a = 6;
console.log(a)
}
</script>
1.3 块级变量
1.ES5中没有块级作用域,ES6中增加了let命令用来声明块级变量
2.块级作用域指的是由花括号限定的作用域,在块级作用域中用let声明的变量就是块级变量
3.块级变量只能在块级作用域中定义和使用,它无法被块级作用域外部所访问
4.用let声明的块级变量不能重定义,如果强行修改,它会报该变量已被声明的错误
5.用var在块级作用域中定义的变量,它可以被外部访问(因为此时它是全局变量)
<script>
{
var a = 1; //可以看作是全局变量
let b = 2; //块级变量
console.log(b)
}
console.log(a)
</script>
1.4 常量
1.常量通过在变量名前面加 const 来定义
2.定义在全局的常量可以被任何位置所访问,定义在块级或局部的常量只能在它定义的作用域中使用
3.常量不能被修改,否则也会报该常量已被声明的错误
<script>
const a = 10;
console.log(a);
function f(){
const b = 1;
console.log(b)
}
{
const c = 2;
console.log(c)
}
</script>
1.5 总结
1.函数内部属于局部作用域,大括号内部属于块级作用域,除此之外的区域就是全局作用域
2.在全局中定义的变量属于全局变量,它可以在页面任何位置被访问
3.在大括号内通过let定义的变量属于块级变量,只能在块级作用域中使用
4.在函数内部定义的变量属于局部变量,只能在函数中使用,当函数被调用之后,除了没有加任何关键字的变量可以被其他作用域访问外,其他的都不能被访问
5.常量无论是在块级作用域还是局部作用域中定义,它都无法被外界访问
6.当需要在块级作用域中定义的变量不想被外界访问时,就通过let来定义;当需要在函数中定义的变量不被外界访问时,就使用var来定义
2.数据类型
1.JavaScript是一种弱类型语言,没有明确的类型分类,不用过分去强调数据类型的分类,根据大体分类,能有助于自己记忆和理解,能够方便、正确灵活的使用就可以
2.我们可以将数据类型分为基本数据类型和引用数据类型两大类
3.基本数据类型:数字类型、字符串类型、布尔类型、Null类型、未定义类型
4.引用数据类型:函数、对象、数组、时间类型等
5.可以通过“typeof(变量名)” 或“typeof 空格 变量名” 来查看变量的数据类型
2.1 基本数据类型
1.数字类型(number)
1.用来表示数值,数值可以是小数也可以是整数,不像其他强类型语言分int/float等等那么细
var n1 = 11;
var n2 = 3.1415926;
console.log(typeof(n1), typeof n2);
2.字符串类型(string)
1.字符串是通过单引号或双引号包裹变量值来赋值的
var s1 = 'aaa';
var s2 = "bbb";
console.log(typeof s1, typeof s2);
2.当需要多行字符串时,可以使用上斜点包裹(反引号),并用冒号来分行
var s3 = `hello:
world`;
console.log(typeof s3);
3.布尔类型(boolean)
1.布尔类型只有两个值:一个是true,一个是false,都是小写
2.布尔值中的true可以转化为数字1,false可以转化为数字0
var b1 = true;
var b2 = false;
console.log(typeof b1, typeof b2);
console.log(b1 + b2);
4.空类型(Null)
1.null是JavaScript保留的关键字,null类型只有一个null值,表示为空或不存在的对象引用
var nu = null;
console.log(typeof nu);
5.未定义类型(undefined)
1.undefined是全局对象Window的一个特殊属性,顾名思义就是未定义的意思,undefined类型也只有一个值,就是Undefined,表示一个变量定义了但未赋值
2.出现undefined的常见情况一般有三种:1)获取一个对象的属性不存在时,返回undefined;2)当函数没有返回值时,返回undefined;3)函数有多个形参,调用函数时,实参数量小于形参数量,那么多出来的形参的参数值就是undefined
var un1;
var un2 = undefined;
function f(){
return
}
res = f();
function f1(n1, n2){
console.log("n1: %s, n2: %s", n1, n2);
}
res1 = f1();
console.log(un1, un2, res, res1);
2.2 引用数据类型
1.函数类型(function)
1.定义一个变量并将整个函数赋值给它,就可以通过这个变量来调用函数了,调用方法也是直接在变量名后面加小括号
var fp = function () {};
console.log(fp, typeof fp); // f(){} "function"
fp();
2.对象类型(object)
1.通过new一个object()函数,得到一个对象类型
2.可以将对象类型看作是字典类型,大括号里面用键值对来作为定义对象的属性,多个属性用逗号隔开
3.对象类型中可以通过key来取值,但是key必须是定义了的数据,而不能是变量名
var obj = new object(); //等同于 var obj = {}
console.log(obj, typeof obj) //{} "object"
var dic = {name: 'king'} //等同于 var dic = {'name': 'king'}
console.log(dic['name'], typeof dic); // king "object"
console.log(dic[name]); //显示为undefined类型
3.数组类型(array)
1.和列表类似,数组的值用中括号包裹,里面用逗号隔开
2.数组本质上是一个对象类型
var arr = [1, 2, 3];
console.log(arr, typeof arr); //(2) [1, 2] 0: 1 1: 2 length: 2 __proto__: Array(0) "object"
4.时间类型
1.时间类型本质上也是对象类型
2.它是通过new加Date()函数来赋值的,可以得到一个当前时间
var d = new Date();
console.log(d, typeof d); // 14:35:11 GMT+0800 (中国标准时间) "object"
2.3 总结
1.数据类型之间可以相互转化,基本上是数字类型、字符串类型以及布尔类型之间的转化:1)布尔类型中的true转化为1,false转化为0,可以与数字类型进行算术运算;2)数字类型中除了0是false,其他数值都是true;3)数字类型与字符串进行加法运算时,得到是将两个值进行拼接后的结果,且为字符串类型;4)数字类型与字符串进行除加法之外的其他运算时,得到的是数字类型,若结果不能转化为具体的数值,则基本上都会转化为NaN
<script>
var a = true;
var b = 2;
console.log(a + b); //3 数字类型
var n1 = 6;
var s1 = 'c';
console.log(n1 + s1); // 6c 字符串类型
console.log(n1/s1); //NaN 数字类型
var s2 = '6';
console.log(n1 - s2); //0 数字类型
</script>
2.一个变量若是Null或是NaN,那么它的布尔值就是false;如果用undefined作为判断语句的条件,它会报“引用错误:未定义”的异常
<script>
if(null){
console.log('null') //不会打印,因为null的布尔值为false
}
if(nan){
console.log('nan') //同上
}
if(undefined){
console.log('undefined') //报错 ReferenceError: Undefined is not defined
}
</script>
3.随机数
1.通过Math中的random()方法可以随机生成一个取得到0,但取不到1的[0, 1)随机数区间
console.log(Math.random()) //[0, 1)的随机数,理论上0可以被取到
2.随机出来的数乘以10,再通过parseInt()函数,则可以生成一个取得到0,但取不到10的[0, 10)整数区间,也就是[0, 9]的整数区间
console.log(parseInt(Math.random())); //只能取到0
console.log(parseInt(Math.random() * 1)); //只能取到0
console.log(parseInt(Math.random() * 2)); //0到1的正整数
console.log(parseInt(Math.random() * 3)); //0到2的正整数
......
console.log(parseInt(Math.random() * 10)); //0到9的正整数
console.log(parseInt(Math.random() * 11)); //0到10的正整数
3.通过反复演算,要想parseInt(Math.random() * number)得到1,则number必须为2;要想得到2,则必须乘以的数是3;要想得到4,则必须number是5;......
4.通过一元一次方程ax+b来思考(a和b都是正整数)如何取到正整数区间[m, n]。x是Math.random(),ax是上述中的parseInt(Math.random() * number),a为number。想取到m,则x是0即可,则b为m,就成了ax+m;要想最大值为n,则ax为n-m就可以了,因此a就是n-m+1
var m_n = parseInt(Math.random() * (n-m+1))+m
console.log(m_n)
5.超大数取整也可以实现[m, n]正整数区间
// (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)
4.运算符
1.算术运算符
**1. + - * / % **
console.log(5/2); // 2.5
console.log(parseInt(5/2)); // 2 取整
console.log(parseFloat(5/2)); // 2.5
console.log(5%2); //1 取余
2.空字符串加数字,会得到字符串,;纯数字字符串前面有加号,会得到数字
res1 = 1 + '';
console.log(res1, typeof res1); // 1 字符串类型
res2 = +'2';
console.log(res2, typeof res2); // 2 数字类型
2.parseInt和parseFloat
1.可以实现字符串转化为数字类型
2.parseInt从头往后找,只找整数部分
3.parseFloat从头往后找,可以找到小数部分,且最多只识别一个小数点
var s = '255.255.255.255string';
res1 = parseInt(s);
res2 = parseFloat(s);
console.log(res1); //255
console.log(res2); //255.255
var s1 = '3a';
console.log(parseInt(s1)); // 3
console.log(parseFloat(s1)); // 3
3.自增自减
1.++在前面的为前自增,++在后面的为后自增
2.前自增的优先级高于一切,也即是先自增,再做其它运算
3.后自增的优先级比赋值符号还低,一般是先运算再自增
num1 = 1;
res1 = ++num1; //会先自增再做赋值运算
console.log(num1, res1); // 2 2
num2 = 1;
res2 = num2++; // 会先做赋值运算,再自增
console.log(num2, res2); // 2 1
4.比较运算符
1. == 只做值的比较;=== 既比较值也比较值的数据类型
2.同理,!= 只做值的比较;!== 既比较值也比较值的数据类型
console.log(5 == '5'); // true 只比较值的大小
console.log(5 === '5'); // false 值和类型都会比较
console.log(5 != '5'); // false 值比较
console.log(5 !== '5'); //true 值比较与类型比较
5.逻辑预算法
1.&& 与,|| 或,! 非
2.用&&时:同时为真才为真,有一个为假即为假
3.用||时:同时为假才为假,有一个为真即为真
4.用 !时:非真即为假,非假即为真
5.短路现象:用&&时,前面为假,后面即使为真也不会执行;用||时,前面为真则短路,后面即使为真也不会执行
var n = 1;
if (false && ++n){
console.log(n)
}
console.log(n) //1
var a = 1;
var b = 1;
if (++a || ++b){
console.log(a, b) // 2 1
}
6.三目运算符
1.语法:条件 ? 结果1 : 结果2
2.如果条件成立则为结果1,否则为结果2
res = (true ? 'yes' : 'no');
console.log(res); // yes
5.流程控制
5.1 分支结构
1.if判断
**1.语法:1) if (条件) {代码块} **
2) if(条件1) {代码块1} else if(条件2) {代码块2} ... else {代码块n}
2.条件中不能直接写成一串,比如1 < a < 3,必须分开写,用逻辑运算符连接:a>1 && a < 3
2.switch
1.语法:
switch (条件){
case 条件1:
代码块1
break; //用来结束case,跳出switch分支结构,多个case分支可以共享一个break
case 条件2:
代码块2
break;
......
default:
代码块n //没有走任何case时,就会进入default分支,如果没有错误情况时可以省略
}
month = parseInt(Math.random() * 13) + 1;
switch (month){
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
console.log('%s月有31天', month);
break;
case 2:
console.log('%s月有28天', month);
break;
case 4:
case 6:
case 9:
case 11:
console.log('%s月有30天', month);
break;
}
5.2 循环
1.for
1.语法:
for (循环变量①; 条件表达式②; 增量③){
循环体④
}
//不推荐
循环变量①
for (; 条件表达式②;){
循环体④
增量③
}
2.生命周期:① ②④③ ②④③ ... ②不成立,退出循环
3.for解决知道循环次数的循环
2.while
1.语法:
循环变量
while (条件表达式) {
循环体
增量
}
2. 1)while解决一切for与do...while能解决的问题(结合函数思想)的循环; 2)解决不知道循环次数的循环(循环用break结束)
3.do...while
1.语法:
循环变量
do {
循环体
增量
} while (条件表达式);
2.do...while会先执行一次循环体,再进行条件判断
4.continue和break
1.continue的作用:跳过本次循环,转而进行下一次循环的判断
2.break的作用:终止循环和switch分支结构
6.函数
1.定义
关键字 函数名(参数列表){
函数体;
返回值
}
function 函数名(参数列表){
代码块;
return 返回值
}
//定义
function add(n1, n2){
return n1 + n2
}
//调用
res = add(1, 2);
console.log(res);
//函数的另外两种定义方式
var 函数名 = 关键字(参数列表){
函数体;
返回值
}
函数名()
var func = function (n1, n2){
console.log('%s %s', n1, n2)
return n1 + n2
}
//分两种情况
//当有函数体时
var 函数名 = (参数列表) => {
函数体;
返回值
}
var func = (n1, n2){
console.log('%s %s', n1, n2)
return n1 + n2
}
//当没有函数体时(连return都可以省略了)
var 函数名 = (参数列表) => 返回值
var func = (n1, n2) => n1 + n2
2.函数成员
1.函数名:用来调用函数,函数名存放的是函数的地址。通过函数名()调用函数
- 1.1 引用(js中的函数也能用来做函数对象)
- 1.2 返回值
- 1.3 参数
- 1.4 容器元素
//函数名的运用(引用)
function add(n1, n2){
return n1 + n2
}
add1 = add;
res1 = add1(10, 20)
console.log(res1)
2.参数列表:将外界资源传入内部的桥梁。你传你的,我收我的(当实参传少了,则未收到参数的形参赋值为undefined;当实参传多了,则多传的实参将会被自动丢弃)
function f(n1, n2){
console.log('n1: %s , n2: %s', n1, n2)
}
f(1, 2) //正常显示
f() //两个undefined
f(5) //n1显示5,n2为undefined
f(11, 12, 13) //只显示 n1: 11, n2: 12
- 2.1 可变长参数,能够接收任意个数的实参
function func(...num){
console.log(num)
}
3.函数体:解决需求的代码块(功能代码块)
4.返回值:将内部数据数据反馈给外部。只能返回一个值,不写或空return时,会返回undefined
3.匿名函数
1.没有声明名字的函数
//注意用分号隔离,也可以单独放在一个标签中,标签会有自己的作用域
(function (){
函数体
返回值
})()
//也可以不写关键字
(()=>{console.log('匿名函数')})()
2.匿名函数调用一次后就会被回收资源
3.匿名函数自定义,可以产生局部作用域与外界隔离,外界不可以直接访问
<script>
(function () {
let number = 666
})()
</script>
<script>
console.log(number) //如果去掉匿名函数,则会打印number
</script>
7.数据类型的运用
1.字符串
// string => str
// 1)声明
// 单引号 | 双引号 | 反引号
// 2)字符串拼接(+)
res = 'you are' + ' ' + 'good man!';
console.log(res);
// 3)字符串的切片(slice)
s = 'you are good man!';
n_s = s.slice(8, 12);
console.log(n_s); // good
// 4)字符串替换(replace)
s = 'you are good man!';
n_s = s.replace('man', 'woman');
console.log(n_s);
// 5)字符串拆分,切分(split)
s = 'you are good man!';
res = s.split(' ');
console.log(res);
// 6)字符串迭代(for(i of str))
s = 'abcdef';
for (num of s) {
console.log(num)
}
2.数组
// array => list
// 1)声明
arr = [1, 4, 2, 3, 5];
console.log(arr);
// 2)反转(reverse)
arr.reverse();
console.log(arr);
// 3)组合(join)
str = arr.join('@');
console.log(str);
// 4)切片(slice)
new_arr = arr.slice(1, 4);
console.log(new_arr);
// 5)排序(sort)
arr.sort();
console.log(arr);
// 6)增删改查
// 6.1 查:只有正向索引
console.log(arr[2]);
// 6.2 增
//尾增(push)
arr.push(888);
console.log(arr);
//首增(unshift)
arr.unshift(666);
console.log(arr);
// 6.3 删
//尾删(pop)
res = arr.pop();
console.log(arr, res);
//首删(shift)
res = arr.shift();
console.log(arr, res);
// 6.4 “增删改”综合方法:splice
//三个参数:开始操作的索引 操作的位数 操作的结果(可变长)
arr = [1, 2, 3, 4, 5];
//数组长度:arr.length
arr.splice(arr.length, 0, 666, 888); //操作的位数指的是被操作的元素个数,如果操作的位数和操作的结果数量不匹配,则以操作的结果为基准
console.log(arr);
arr.splice(0, 2, 6, 6);
console.log(arr);
3.字典
// object => dict // 本质是对象
// 1)定义
height = 172;
dic = {
'name': 'king',
age: 26, // 所有的key(属性名)都是字符串类型,所以可以省略引号
height, // 当value为变量,且变量名与key同名,可以省略value
};
console.log(dic);
// 2)访问
console.log(dic.name); //可以通过“.属性”来访问对象的属性
console.log(dic['age']); // 通过key来取值
// 3)增删改
// 增(增加属性)
dic.gender = '男';
console.log(dic);
// 删(delete)
delete dic.gender;
console.log(dic);
// 改(直接通过属性名来更改属性值)
dic.name = 'Nick';
console.log(dic);