第七十篇 js基础

一、前言

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 {
            width: 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 {
            width: 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 {
            width: 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);
posted @ 2019-08-07 15:34  newking_itman  阅读(214)  评论(0编辑  收藏  举报