JS 介绍

一、 Javascript

(1) JS 简史

在 WEB 日益发展的同时,网页的大小和复杂性不断增加,受制于网速的限制,为完成简单的表单验证而频繁地与服务器交换数据只会加重用户的负担,当时走在技术革新最前沿的 Netscape(网景) 公司,决定着手开发一种客户端语言,用来处理这种简单的验证。
1995年,就职于 Netscape 公司的布兰登·艾奇,开始着手为即将于1996年2月发布的 Netscape Navigator 2 浏览器开发一种名为 LiveScript 的脚本语言。为了尽快完成 LiveScript 的开发,Netscape 与 Sun 公司建立了一个开发联盟。在 Netscape Navigator 2 正式发布前夕, Netscape 为了搭上媒体热炒 Java 的顺风车,临时把 LiveScript 改名为 JavaScript。

由于Javascript1.0获得的关注度越来越高,1996年,微软就在其 Internet Explorer3 中加入了名为 JScript 的 JavaScript 实现,这意味着有了两个不同的 JavaScript 版本,导致 JavaScript 没有一个标准化的语法和特性。

1997年,以 JavaScript 1.1 为蓝本的建议被提交给了欧洲计算机制造商协会(ECMA)。该协会指定 39 号技术委员会(TC39) 负责 标准化一种通用、跨平台、供应商中立的脚本语言的语法和语义。 TC39 由来自 NetScape、Sun、微软、Borland 及其他关注脚本语言发展的公司的程序员组成,他们经过数月的努力完成了 ECMA-262 标准,定义一种名为 ECMAScript 的新脚本语言。

布兰登·艾奇(1961年~),JavaScript 的发明人,目前(2005年至2014年) 在 Mozilla 公司担任 CTO。2014年4月3日,出任Mozilla 的CEO 十天就被迫辞职。

(2) ECMAScript 版本发展

1998年6月,ECMAScript 2.0版发布。
1999年12月,ECMAScript 3.0版发布,成为JavaScript的通行标准,得到了广泛支持。
2007年10月,ECMAScript 4.0版草案发布,对3.0版做了大幅升级。草案发布后,由于4.0版的目标过于
激进,各方对于是否通过这个标准,发生了严重分歧。以Yahoo、Microsoft、Google为首的大公司,
反对JavaScript的大幅升级,主张小幅改动;以JavaScript创造者Brendan Eich为首的Mozilla公司,则
坚持当前的草案。
2008年7月,由于各方分歧太大,争论过于激进,ECMA开会决定,中止ECMAScript 4.0的开发,将其
中涉及现有功能改善的一小部分,发布为ECMAScript 3.1,而将其他激进的设想扩大范围,放入以后的
版本,由于会议的气氛,该版本的项目代号起名为Harmony(和谐)。会后不久,ECMAScript 3.1就
改名为ECMAScript 5。
2009年12月,ECMAScript 5.0版正式发布。Harmony项目则一分为二,一些较为可行的设想定名为
JavaScript.next继续开发,后来演变成ECMAScript 6;一些不是很成熟的设想,则被视为
JavaScript.next.next,在更远的将来再考虑推出。
2011年6月,ECMAscript 5.1版发布,并且成为ISO国际标准(ISO/IEC 16262:2011)。
2013年3月,ECMAScript 6草案冻结,不再添加新功能。新的功能设想将被放到ECMAScript 7。
2013年12月,ECMAScript 6草案发布。然后是12个月的讨论期,听取各方反馈。
2015年6月17日,ECMAScript 6发布正式版本,即ECMAScript 2015。
2015版本也就是6版本,将来在我们最后面的课程

(3) js 的应用

  • 数据验证
  • 读写HTML元素、动态的修改样式
  • 与用户进行交互
  • 网页特效
  • WEB 游戏制作
  • 基于Node.js 技术进行服务器端编程

(4) ECMAScript 脚本语言

Javascript,JScript,ActionScript等脚本语言都是基于ECMAScript标准实现的。
在JavaScript,JScript和ActionScript中声明变量,操作数组等语法完全一样,因为它们都是
ECMAScript。但是在操作浏览器对象等方面又有各自独特的方法,这些都是各自语言的扩展。
JavaScript 是由ECMAScript 核心语法,DOM 和 BOM 三者组成的。
ECMAScript 核心语法: JS 语法格式、常量变量、数据类型、流程语句、函数、内置对象等
BOM: Browser Object Model 浏览器对象模型 封装的是操作浏览器相关的 API
DOM: Document Object Model 文档对象类型 封装的是操作文档相关的 API

在这里插入图片描述

二、 javascript 基础

(1) JS 语法

  • 每一条 JS 语句必须以分号结束
  • 严格区分大小写 例如: a 和 A 是两个完全不同的东西
  • 忽略所有的换行和空格 它们存在的目的就是为了提高程序的可读性

(2) JS 中的注释

  • html 中的注释: <!-- 注释内容 -->
  • css 中的注释: /* 注释文本 */
  • js 中的注释
    • // 单行注释
    • /* 多行注释 */

(3) js 的引入

  • 行内方式: 借助的是 html 中的事件属性 如: onmouseover onmouseout onclikc 等
  • 嵌入 script 代码: 借助 script 标签,在 script 标签内书写 js 代码
  • 引入外部的 JS 代码: 借助 script 标签,引入外部独立的 js 文件

注: script 标签可以嵌入到 html 文档的任何位置
一个 html 文件中,可以嵌入多个 script 标签
通过 src 属性引入外部 js 文件的 script 标签内不能再去书写 js 代码

(4) 数据输出的方式

  • alert() 警告框 效果: 回向页面弹出一个弹框,必须点击确定才能继续执行代码;会有阻塞的效果
  • console.log() 控制台打印日志
    在这里插入图片描述

三、常量

(1) 概述

常量: 又称字面量,字面的意思就是看到什么就是什么.在程序执行过程中不会发生改变.

常量分为:数值常量、字符串常量、布尔值常量等

(2) 数值常量

数值: 整数(10,23) 、 浮点数(1.34, 3.14 )
生活中常见的进制数是十进制数,由0-9之间的数字组成,锋十进一 如: 10 20 34 56 等等
程序中除了十进制外,可能还会碰到二进制、八进制、十六进制等进制
计算机底层的运算,使用的是二进制补码的形式进行运算

二进制,由 0 和 1 组成, 前缀标识为 0b 如: 0b 1000 0111

八进制,由 0-7 之间的数字组成,前缀标识 0、0o 、0O 如: 0o76

十六进制,由 1-9,a-f 组成,a-f 代表的是 10-15 之间的数字,前缀标识 0x 如: 0xa1f6

(3) 字符串常量

双引号或单引号进行包裹的文本 例如: “Hello” “您好” ‘男’

如果想要添加一些特殊的符号,需要借助转义字符 “” , 如下

\n  换行
\t  制表符
\r  回车
\"  "" 
\'  ''
\\  \

(4) 布尔值常量

布尔值有且只有两个: truefalse

四、变量

(1) 概述

变量: 用来存储信息数据的容器。在程序执行过程中,可以发生改变

信息数据: 可以是上面讲过的常量、也可以是后面要讲的函数、数组、正则等等所有的东西

(2) 变量的声明

变量使用关键字 var 进行声明

语法格式 var 变量名 = 初始化值;

解释 将赋值运算符 “=” 右边的初始化值 赋给 左边使用 var 声明的变量,那么此时这个变量在内存中开辟一个空间,存储初始化值。
举例 var str= “Hello”; var num = 10;

//第一步:使用var关键字声明一个变量, 变量名为 num 
// var num; 
// console.log("num:",num); //num: undefined undefined未被定义的 
//第二步:对声明的变量进行赋值 将字面量 10 赋给变量 num 
// num = 10;
// = 赋值运算符 运算顺序:从右向左 
// console.log("num:",num); //num: 10 

//上面两步可以简写为一步 
var num = 10;
console.log("num:", num);//num: 10

(3) 变量的命名规则

  • 由数字、字母、下划线以及美元符号($) 组成
  • 数字不能开头
  • 不能是 JS 中的关键字和保留字
  • 见名知意
  • 驼峰式命名: 首字母小写,多个单词,从第二个单词开始首字母大写 如: getMaxNum
  • 尽可能简化命名的长度

(4) 多个变量的声明方式

  • 第一种:每一个都是 var 声明,分号结束
  • 第二种: 如果是连续声明多个变量,可以使用一个 var, 变量之间使用逗号隔开,最后分号结束即可
// 多个变量的声明方式一
// var a = 1;
// var b = 2;
// var c = 3;

// 多个变量的声明方式二
var a = 10,b=20,c=30;
console.log("a:",a,"b:",b,"c:",c);

(5) 变量的提升

我们可以用先使用后面声明的变量,即使变量有赋值,也是 undefined

// console.log(a); 
// 报错:  a is not defined  在整个程序中,不管是调用前还是调用后,都不存在这个变量的声明,直接调用会报错

// 先声明变量 b  并赋值 10 
var b = 10;
// 再调用
console.log(b);  // 10 


// 变量的提升演示
// 先调用
console.log(c); // undefined
// 再声明变量 c  并赋值 20 
var c= 20;
console.log(c); // 20 

变量提升的原因:
浏览器中的 JS 引擎,在解析 JS 代码时,分成两步: 预解析阶段运行阶段

预解析阶段: 会审查 js 中是否有声明语句,如果有,就将其提升到当前作用域内所有 JS 语句的顶部

运行阶段: 进行赋值操作

所以上面,变量的提升演示部分代码,等价于下面的代码

var c;
console.log(c);// undefined

c = 20;
console.log(c);// 20 

五、 变量数据类型

变量的数据类型分为两大类:基本数据类型引用数据类型

(1) 基本数据类型

  • Number 数值类型: 整数 10, 20 小数 10.23 3.14 Infinity 无穷大 NaN(Not a Number) 不是一个数字
  • String 字符串类型: 双引号或者单引号包裹的文本 如: var str = “Hello”; 那么变量 str 的数据类型就是字符串类型
  • Boolean 布尔类型: 有且只有两种值 true 和 false
  • Null 空类型: 空指针对象 它是一个特殊的对象
  • Undefined 未被定义的: 变量被声明,但是没有被赋值

(2) 引用数据类型

  • Object 对象类型(所有内置对象都是这个类型,如:数字 Array 对象、字符串String对象、RegExp对象等)
  • Function 函数类型

六、数据类型检测

通过 typeof 关键字进行检测,检测语法如下
typeof 变量名
typeof(变量名)

// 数值类型
var a = 10, b = 3.14;
console.log("a:", a, "数据类型是:", typeof a, ",b:", b, "数据类型是:", typeof (b));
// a: 10 数据类型是: number ,b: 3.14 数据类型是: number 

a = Infinity;
b = NaN;
console.log("a:", a, "数据类型是:", typeof a, ",b:", b, "数据类型是:", typeof (b));
// a: Infinity 数据类型是: number ,b: NaN 数据类型是: number

console.log("10/0=",10/0); // 10/0= Infinity
console.log(10 - "hehe"); // NaN

// 字符串类型
a = "hello";
b = '1000';
console.log("a:", a, "数据类型是:", typeof a, ",b:", b, "数据类型是:", typeof (b));
//a: hello 数据类型是: string ,b: 1000 数据类型是: string


// 布尔类型
a = true;
b = false;
console.log("a:", a, "数据类型是:", typeof a, ",b:", b, "数据类型是:", typeof (b));
//a: true 数据类型是: boolean ,b: false 数据类型是: boolean 

// Null 空指针类型
a = null;
// Undefined 未被定义的
b = undefined;
console.log("a:", a, "数据类型是:", typeof a, ",b:", b, "数据类型是:", typeof (b));
//a: null 数据类型是: object ,b: undefined 数据类型是: undefined

var c;
console.log(c); // undefined

七、数据类型之间的转换

(1) 隐式转化

借助的是运算符 + - * / % 等等
运算符 + 可以是: 数学的加运算、有字符串存在的情况下是字符串拼接运算、正号

var a = 10,
    b = "20",
    c = 10.4;
console.log("a+b+c=", a + b + c); // a+b+c= 102010.4 
console.log("a+c+b=", a + c + b); // a+c+b= 20.420
console.log("b+a+c=", b + a + c); // b+a+c= 201010.4
console.log(a + c); // 20.4 
console.log(+b); // 20 
console.log(a - b);  // -10
console.log(10 - true);  // 9
console.log(10 - false); // 10 
console.log(10 - "a"); // NaN
console.log(10 - ''); // 10 
console.log(10 - null); // 10 
console.log(10 - undefined); // NaN 

(2) 显式转换

借助内置的方法或者包装类实现
内置方法:

  • parseInt() 将其他数据类型转为整数类型; 数值的取整
  • parseFloat() 将其他数据类型转为浮点数类型;浮点数
  • toString() 将其他数据类型转为字符串类型

包装类:

  • Number() 将其他数据类型转为数值类型
  • String() 将其他数据类型转为字符串类型
  • Boolean() 将其他数据类型转为布尔值类型
var a = 10,
    b = true,
    c = "hello100",
    d = "100hello";
// toString()  转为字符串的方法
console.log(a.toString(),"数据类型:",typeof(a.toString()));  // 10 数据类型: string 
console.log(b.toString(),"数据类型:",typeof(b.toString()));  // true 数据类型: string


// parseInt() 转整数
console.log(parseInt(10.23));  // 10 
console.log(parseInt(b)); // NaN
console.log(parseInt(c)); // NaN 
console.log(parseInt(d)); // 100


// parseFloat()  转浮点数  用法同 parseInt()


// Number()  将其他数据类型转为数值类型
console.log(Number(b)); // 1
console.log(Number(c)); // NaN 
console.log(Number(d)); // NaN
console.log(Number(false)); // 0
console.log(Number('')); // 0
console.log(Number(null));  // 0
console.log(Number(undefined)); // NaN
console.log(Number("100")); // 100


// String()  将其他数据类型转为字符串型


// Boolean()  将其他数据类型转为布尔类型  布尔只有两个值 true  和 false
console.log(Boolean(a)); // true
console.log(Boolean(1)); // true
console.log(Boolean(c)); // true
console.log(Boolean(d)); // true


console.log(Boolean(0));  // false
console.log(Boolean(''));  // false
console.log(Boolean(null));  // false
console.log(Boolean(undefined)); // false
console.log(Boolean(NaN)); // false

八、 prompt

prompt() 信息提示框:提示用户在指定的输入框内输入信息
prompt(msg,ipt) 方法
参数

  • msg 设置文本提示信息,字符串类型
  • ipt 输入框中的内容,字符串类型
    返回值 返回用户输入的数据,字符串类型
// 声明一个变量 sex  来接收用户输入的 性别
var sex = prompt("请输入您的性别", "女");
console.log(sex);

// 声明一个变量 num  来接收用户输入的 年龄
var num = prompt("请输入您的年龄", "20");

num = parseInt(num);
console.log(num);

在这里插入图片描述

九、运算符

(1) 算术运算符

算术运算符用来执行数学运算.
生活中常见的算术运算符有: + - * / %(取模,取余数)

// 算术运算符
// 表单式分为运算元和运算符
// JS 中算术运算符: + -  *  /  %  ++  -- 
// + 除字符串类型外参与的运算,执行数学运算  
// true  隐式转换成数字 1  进行数学运算 
// false 隐式转换成 0  进行数学运算
console.log(10 + 20); // 30
console.log(10 + 4.6); // 14.6
console.log(10 + true); // 11
console.log(10 + false); // 10 
console.log(10 + null); // 10
console.log(10 + undefined);// NaN


// + 作为正号进行运算
console.log(+10); // 10 
console.log(+"10"); // 10
console.log(+"10abc"); // NaN
console.log(+true); // 1
console.log(+false); // 0
console.log(+null); // 0
console.log(+""); // 0
console.log(+undefined);// NaN


// + 字符串参与的多元运算,属于字符串拼接
console.log(10 + ''); // "10"    string
console.log(10 + "10"); // "1010"
console.log("10" + 10); // "1010"
console.log("10" + true); // "10true"
console.log("10" + false); // "10false"
console.log("10" + null); // "10null"
console.log("10" + undefined); // "10undefined"
console.log("10" + NaN); // "10NaN"


// -  *  /  %   
// true 隐式转换成数字 1 进行数学运算
// false 和 null 隐式转换成 0 进行数学运算 
// undefined 参与的都是 NaN
console.log(10 - 5); // 5
console.log(0.3 - 0.1); // 0.19999999999999998
console.log(10 * "10"); // 100  Number  除了 + 之外的其他数学运算,字符串或者其他非数值类型都会隐式转为数值类型进行运算
console.log(10 * "10abc"); // NaN
console.log(10 - ""); // 10
console.log(10 - false); // 10
console.log(10 / true); // 10
console.log(10 / null); // Infinity  无穷大
console.log(10 / undefined); // NaN
console.log(10 % null); // NaN

“+” 运算可以作为:加法运算、正号、字符串参与的运算作为字符串拼接
++(自增) --(自减)

// 前++  前--
var a = 1,
    b = 2;
console.log("a:", a, "b:", b); // a: 1 b: 2

--a; // 等价于 --a => a = a - 1
++b; // 等价于 ++b => b = b + 1
console.log("a:", a, "b:", b); // a: 0 b: 3

a = --a;
console.log("a:", a, "b:", b); // a: -1 b: 3

var c = ++b;
console.log("a:", a, "b:", b); // a: -1 b: 4


// 后++  后--
var i = 1,
    j = i;
console.log("i:", i, "j:", j); // i: 1 j: 1

i--; // 等价于  i-- => i = i-1;
j++; // 等价于  j++ => j = j+1;

console.log("i:", i, "j:", j); // i: 0 j: 2 
// 总结: 根据实践结果,在自身操作前++  和 后++   前-- 和 后--问题上,没有什么区别

// 第三方变量参与时,就不同了,如下观察结果
var s = j++; // 1 先赋值  2 再加加
console.log("i:", i, "j:", j, "s:", s); // i: 0 j: 3 s: 2


i = i--; // 脑残面试官才会问的问题
console.log("i:", i, "j:", j, "s:", s);  // i: 0 j: 3 s: 2

// 数学中的运算顺序: 先乘除后加减
// 程序中的运算同样是有顺序的: 如上面的算术运算符,
// 优先级  前++、前--、正负号(+-) >>  * / %  >> + - >> 赋值运算符 = >> 后++  后--

(2) 比较运算符

比较运算符也叫关系运算

比较运算符比较的结果是一个布尔值

比较运算符有: > < >= <= ==(等于) !=(不等于) ===(全等于) !==(全不等于)

// 纯数值进行比较  按照值得大小
console.log(10 > 20); // false
console.log(3.14 == Math.PI); // false

// 数值和其它基本数据类型进行比较  将其他类型转为数值类型进行运算
console.log(10 > "5"); // true
console.log(10 > "10ab"); // false
console.log(10 < "10ab"); // false
console.log(10 == "10ab"); // false
console.log(1 == true); // true
console.log(0 == false); // true
console.log(0 == null); // false
console.log(1 === true);// false
// "==" 比较值是否相同,忽略了数据类型
// "==="  比较的是值和数据类型是否完全相同

console.log(10 >= 10); // true
// true  等价于  判断 10 大于 10 或者 10 等于 10 吗?

console.log(null === null); // true
console.log(undefined === undefined); // true
console.log(NaN === NaN); // false
console.log(Infinity === Infinity); // true

console.log(null == undefined); 
// true ES3 中,才新增 undefined 数据类型,这个数据类型衍生自 null  所以在比较值的时候它们是相同的

console.log(null === undefined);
// false  数据类型不同   null 数据类型为 "object"  undefined 数据类型为  "undefined"

// 数字字符串之间的比较  按照 ASCII 码从左向右逐个进行比较表进行比较  ASCII 码表中 0-9 对应的 ASCII 值 48-57
console.log("24" > "15"); // true
console.log("10" > "5"); // false
console.log("234" > "25"); // fasle

(3) 逻辑运算符

逻辑运算符优先级 ! >> && >> ||

用来进行逻辑运算,运算符有: & && | || !(逻辑非)

① 逻辑 与 &&

将逻辑与比喻成串联电路,判断过程,想象成电流通过的过程
在这里插入图片描述
电流通过: 如果 a 为真,电流能够通过流通到 b,结果就是 b; 如果 a 为假,电流不能通过,停留在 a , 结果为 a.

② 逻辑或 ||

将逻辑或比喻成并联电路,判断过程,想象成电流通过的过程.
在这里插入图片描述
电流经过时:如果 a 为真,电流直接从 a 完成循环,结果为a; 如果a 为假,电流从 a 不能经过,流经到 b,我们结果是 b

真值表

逻辑与 && 运算: 两边都为真才是真,有一个为假则为假
在这里插入图片描述
逻辑或 || 运算: 有一个为真即为真,两边都为假结果才为假
在这里插入图片描述

// 逻辑运算符:
// 逻辑与( &  && ) 同时满足才满足  
// 逻辑或( |  || ) 只要有一个满足即满足   

// &&  或 ||  具有短路效果,可以提高程序的执行效率  短路效果解释
// 逻辑与  两边同时满足才满足
// 当第一个值是 true 的 情况下,第二个值决定最终效果
console.log(true && false); // false
console.log(true && true); // true
// 当第一个值不成立,那么使用 && 的情况下,就不需要再进行后面的判断就能直接得出结果不满足
console.log(false && true); // false


// 逻辑或  有一个满足即满足
// 当第一个值是 false 的情况下,第二个值决定最终结果
console.log(false || true); // true
console.log(false || false); // fasle
// 当第一个值条件成立,最终结果就是成立的,那么就不需要再去判断后面的结果了
console.log(true || false); // true


// 上面 || 和 && 进行运算,最终结果是 true 或 false
// 如果使用 | 和 & 进行布尔运算  最终结果是 0 或 1 
console.log(true | false); // 1
console.log(true & false); // 0 

③ 逻辑 !(非)

// 逻辑非(!)

console.log(true); // true
console.log(!true); // false

console.log(10); // 10
console.log(!10); // fasle
console.log(-10); // -10
console.log(!(-10));// false
console.log(0); // 0
console.log(!0); // true
// 除了 0 之外的所有数字,进行逻辑非操作,得结果都是 false

console.log("hello"); // "hello"
console.log(!"hello"); // false
console.log(""); // ""
console.log(!""); // true
// 非空字符串进行逻辑非操作,所得结果都是 false


console.log(null); // null
console.log(!null); // true
console.log(undefined); // undefined
console.log(!undefined); // true
console.log(NaN); // NaN
console.log(!NaN); // true

所有的基本数据类型进行逻辑运算时,如何进行运算:

// 总结: 数值 0 、空字符串 "" 、null 、undefined 、NaN 、
// false 都被当作条件不成立,在进行逻辑非操作时返回 true
console.log(10 && 5); // 5
console.log(10 && 0);// 0

console.log(10 && "hello");// "hello"
console.log("" && "hello");// ""


console.log("" || "10"); // "10"
console.log("" || null); // null

console.log(undefined && null); // undefined

练习:

false || !false && false || true;
= false || true  && false || true
= false || false || true
= false || true
= true

4 && "hello" || !false || !true && null
= 4 && "hello"  || true || false && null
= "hello" || true  || false
= "hello" || false
= "hello"

(4) 赋值运算符

不同于前面运算符运算符从左往右,赋值运算符运算顺序是从右往左的

如: var num; num = 10; 将右边的字面量10赋给左边的变量 num

赋值运算符: =、 +=、 -= 、 *= 、 /= 、 %= 、

// 声明一个变量 num
var num;
console.log("num",num); // undefined

// 赋值运算符: = 、+= 、-= 、 *= 、 /= 、 %=
// 对变量  num 进行赋值操作
num = 10;
console.log("num:",num); // 10

num+=20;// 等价于  num = num + 20
console.log("num:",num); // num:30

num*=10;// 等价于  num = num * 10
console.log("num",num); // num: 300

num%=7; // 等价于  num = num % 7
console.log("num",num); // num:6

num /=3; // 等价于  num = num / 3
console.log("num",num); // num:2

(5) 运算符的优先级

运算优先级: 贴身(前++、前 - -、正+、负-、逻辑非!) >>> 算术运算符(先乘除后加减) >>> 比较运算符(先 > >= < <=,再 == ! =) >> 逻辑运算符(先逻辑与&&,再逻辑或 ||) >>> 赋值运算符 >>> 后++、后 - -
运算顺序: 除赋值运算符运算顺序从右往左,其它都是从左往右
在这里插入图片描述

(6) 三元运算符

语法: 条件表达式 ? 条件表达式成立执行的语句 : 条件表达式不成立执行的语句

var a = 100, b = 50;
var maxNum = a > b ? a : b;
console.log("a 与 b 中的最大值是:",maxNum);// a 与 b 中的最大值是: 100

(7) 运算符综合练习

// 习题一
var a = 4;
var sum = 1 * (2 + 3) && a++ || 5 > 6 && 7 < 8 || 9
        = 1 * 5 && a++ || 5 > 6 && 7 < 8 || 9
        = 5 && a++ || 5 > 6 && 7 < 8 || 9
        = 5 && a++ || false || 9
        = a++ || false || 9
        = a++ || 9
        = a++
sum = a++;// 后++ 存在的赋值操作,先赋值,再自增
sum = a = 4;
a++ <==> a + 1=4 + 1=5

// 习题二
var a = 4;
var sum = 1 + 2 && 3 * a++ % 5 || 6 < 7 == 8 / !false
        = 1 + 2 && 3 * a++ % 5 || 6 < 7 == 8 / true //  3 * a++ =>3 * a =3 * 4 =12
        = 1 + 2 && 2 || 6 < 7 == 8
        = 3 && 2 || 6 < 7 == 8
        = 3 && 2 || true == 8
        = 3 && 2 || false
        = 2 || false
        = 2

最后: a++ <==> a = a + 1 = 4 + 1 = 5

习题三
当工作年限不满1年,工资小于8000,年终奖为工资的 1 倍,否则是1.2 倍,
当工作年限不满2年,工资小于10000,年终奖为工资的 1.5 倍,否则是1.7倍,
当工作年限为超过2年,工资小于 13000,年终奖为工资的 2.3 倍,否则是 3 倍,
用户输入年限,工资,输出年终奖

// 第一步:定义两个变量来接收用户输入的年限 和 当前 薪资
var jobYear = Number(prompt("请输入您的工作年限", "2"));

var salary = Number(prompt("请输入您当前的薪资", "10000"));

// 第二步: 利用三元运算符,判断各种条件,给出对应的年终奖
// 判断工龄年限是否满一年
// var result = jobYear < 1 ? "工作年限不满1年" : "工作年限满1年";

// 入如果工作年限满一年,判断工资是否小于 8000
// var result = jobYear < 1 ? (salary < 8000 ? "工资小于8000" : "工资不小于8000") : "工作年限满1年"


// 当工作年限不满一年,工资不小于 8000,年终奖为工资的 1 倍,否则是 1.2 倍
// var result = jobYear < 1 ? (salary < 8000 ? salary * 1 : salary * 1.2) : "工作年限满一年"

// 当工作年限不满两年,工资小于 10000,年终奖为工资的 1.5 倍,否则是 1.7倍
// var result = jobYear < 1 ? (salary < 8000 ? salary * 1 : salary * 1.2) : (jobYear < 2 ? (salary < 10000 ? salary * 1.5 : salary * 1.7) : "工作年限超过两年")

// 当工作年限超过两年,工资小于 13000,年终奖为工资的  2.3 倍,否则是 3 倍
var result = jobYear < 1 ? (salary < 8000 ? salary * 1 : salary * 1.2) : (jobYear < 2 ? (salary < 10000 ? salary * 1.5 : salary * 1.7) : (salary < 13000 ? salary * 2.3 : salary * 3))

console.log("result", result);

十、Math 对象

这是 JS 中内置的一个对象,叫做算术对象

Math 对象用于执行数学任务

只要是对象,那么就具有特征与行为,体现到程序中就是属性和方法

Math 对象作为 JS 中的内置对象,给它内置了很多属性和方法.

Math 将自己本身当作对象,可以直接调用这些属性和方法

Math 对象调用属性和方法的方式 Math. 属性 Math.方法()

(1) Math 对象的属性

PI 获取圆周率 Π=3.14…

(2) Math 对象的方法

  • random() 获取 0-1 之间的随机数 左闭右开[0,1)
  • round(num) 获取参数 num 的四舍五入的值
  • pow(x,y) 获取 x 的 y次幂
  • sqrt(num) 获取参数 num 的开平方根
// 获取圆周率 Π=3.14....
console.log(Math.PI);
// 3.141592653589793  JS在中只能获取到小数点后15位

// pow(底数x,底数y)  获取x 的 y 次方
console.log(Math.pow(2, 4)); // 16 

// sqrt(num)  获取开平方
console.log(Math.sqrt(9)); // 3

// random()  获取[0,1) 之间的随机数
console.log(Math.random()); // 每次结果不同


// 获取[0,10) 之间的随机整数
console.log(Math.random() * 10);

// 获取[0,10) 之间的随机整数
console.log(parseInt(Math.random() * 10));

// 获取[0,10) 之间的随机整数
console.log(Math.round(Math.random() * 10));

// 获取 [10,20) 之间的随机整数
console.log(parseInt(Math.random(20) * 10 + 20));

十一、条件语句

条件 if 语句, 用来指定符合条件后需要执行的语句,不符合条件不执行.
类似于选择器,选择正确的答案,必须符合题干条件.
条件语句有很多种语法格式,如下:

  • 只有 if 关键字的条件语句

if(条件表达式){
当条件表达式成立的情况下才会执行的语句
}

案例:判断一个人的年龄是否满 18 岁,如果满足了,那么可以进入网站观看暴力电影

var age = parseInt(prompt("请输入您的年龄", "18"));
if (age >= 18) {
    alert("可以观看")
}

满足条件,执行大括号中的语法体;不满足条件,跳出 if 语句,继续执行 if 语句后面的代码

  • 存在 else 的 if 语句

if(条件表达式){
当条件表达式成立的情况下会执行的语句
} else {
当条件表达式不成立执行的语句
}

案例: 判断一个人的年龄是否满18岁,如果满足了,那么可以进入网站观看暴力电影;如果不满18岁,提示请在家长陪同下进行观看

var age = parseInt(prompt("请输入您的年龄", "18"));

if (age >= 18) {
    alert("可以观看")
} else {
    alert("警告,请在家长陪同下进行观看")
}

if…else 语句可以和 三元运算进行转换,将上面的代码利用三元进行简化

age >= 18 ? alert("可以观看") : alert("警告,请在家长陪同下继续观看")
  • if else 存在的多条判断语句

if (条件一) {
条件一满足执行的语句体
} else if (条件二) {
不满足条件一,满足条件二执行的语句体
}…else if (条件N) {
不满足N之前的条件,满足条件N执行的语句体
} else {
以上所有的条件都不满足执行的语句
}
练习: 假设公司员工可以根据工龄,领取对应的福利商品:满10年的老员工,发红包2万元,购物卡1000元一张;满5年但是不满10年的老员工,发红包8000元,购物卡1000元一张;满3年但是不满5年的老员工,发红包3000元,购物卡800元一张; 满1年但是不满3年的老员工,购物卡1500元一张;不满一年的员工,购物开300元两张。

var jobYear = Number(prompt("请输入您的工作年限", "3"));

if (jobYear >= 10) {
    alert("红包2万元,购物卡1000元一张")
} else if (jobYear >= 5) {
    alert("红包8000元,购物卡1000元一张")
} else if (jobYear >= 3) {
    alert("红包3000元,购物卡 800 元两张")
} else if (jobYear >= 1) {
    alert("购物卡1500元一张")
} else if (jobYear < 1 && jobYear > 0) {
    alert("购物卡300元两张")
} else {
    alert("输入有误,请重新输入!!!!")
}

// 注: if 语句最终只会执行一个满足条件的大括号中的语句


// 省略大括号的情况
// 如果 if 语句中只有一条循环语句可以省略大括号
if (jobYear >= 10)
    alert("红包2万元,购物卡1000元一张")
else if (jobYear >= 5)
    alert("红包8000元,购物卡1000元一张")
else if (jobYear >= 3)
    alert("红包3000元,购物卡 800 元两张")
else if (jobYear >= 1)
    alert("购物卡1500元一张")
else if (jobYear < 1 && jobYear > 0)
    alert("购物卡300元两张")
else
    alert("输入有误,请重新输入!!!!")


// 如果有两条执行语句,省略大括号的情况下,直接报错
// 如果 if 中有两条语句.进行省略,那么不能达到想要的结果,直接报错:
var flag = true;
if(flag)
    console.log(111);
    console.log(222);
else 
    console.log(333);
    console.log(4444);

// Uncaught SyntaxError: Unexpected token 'else'

十二、选择语句

switch语句,这是一个选择语句,根据条件去匹配对应的值,匹配成功,执行这条匹配下的语句

  • 语法格式
    switch (表达式) {
    case 值1:
    语句体1;
    break;
    case 值2:
    语句体2;
    break;

    case 值N:
    语句体N;
    break;
    default:
    以上都不满足执行的语句体;
    break;
    }
    注: default 语句可以写在 switch 中的任何位置,都是在 case 值都匹配不到的时候执行,习惯上放到最后。
    default 也可以省略,当不满足所有 case 时,不执行任何操作,直接跳出 switch
    break 是控制语句,打断的意思;这里用来跳出 switch 语句。也就是遇到 break 语句就结束了.
    练习: 输入 1-7 之间的数字,判断今天是星期几
var day = parseInt(prompt("请输入1-7之间的整数", "5"));

switch (day) {
    case 1:
        alert("今天是周一");
        break;
    case 2:
        alert("今天是周二");
        break;
    case 3:
        alert("今天是周三");
        break;
    case 4:
        alert("今天是周四");
        break;
    case 5:
        alert("今天是周五");
        break;
    case 6:
    case 7:
        alert("今天是周末");
        break;
    default:
        alert("输入有误,请重新输入");
        break;
}

  • 变种
    switch 中表达式书写 true,在 case 后面去写条件表达式。 当 case 后面条件表达式成立,即执行对应的语句体,否则继续向下匹配,直到匹配成功,遇到 break 跳出
    练习: 根据用户输入的性别和年龄,判断用户是否满足结婚年龄(男:23 女:20)
var sex = prompt("请输入您的性别", "男");
var age = Number(prompt("请输入您的年龄", "30"));
switch (true) {
    case sex == "男":
        switch (true) {
            case age >= 23:
                alert("男生符合结婚要求");
                break;
            default:
                alert("男性必须满足 23 周岁才可以结婚");
                break;
        }
        break;
    case sex == "女":
        switch (true) {
            case age >= 20:
                alert("女生符合结婚要求")
                break;
            default:
                alert("女性必须满足 20 周岁才可以结婚");
                break;
        }
        break
}

十三、循环语句

循环指的其实就是只要符合一定的条件,就会不停的执行某个动作.直到通过外力或者不符合条件后,才会结束循环
在程序中的循环有三种: while 循环、 do…while 循环、 for 循环

(1) while 循环

语法格式:
while(条件表达式){
当条件表达式成立,执行此循环
}

练习: 循环输出 100 次 “Hello World!!”

// 声明一个变量 i ,并设置初始值 0 
var i = 0;
while(i<100){
    console.log("Hello World!!");
    // 对变量进行操作
    i++; // i = i + 1
}

执行顺序:

  • 先定义表达式需要的变量,并赋初始值 var i = 0;
  • 判断 while 循环中的表达式 i < 100 是否成立
  • 如果表达式成立,那么执行大括号中的循环体语句
    console.log(“Hello World!!”);
    并从循环体中,改变控制条件的变量的值 i++
  • 重复执行 第2步、第3步,直到 while 循环中的表达式 i < 100 不成立,跳出循环为止

练习: 循环输出 1-100 之间的所有整数(使用 while 循环实现)

var i = 1;
while(i<=100){
    console.log("第" + i + "次打印;");
    i++;
}
console.log("i:",i); i:101

(2) do…while 循环

语法格式
do{
循环体
}while(条件表达式);
不难发现, do…while 和 while 循环最大的区别在于: do…while 不管条件是否成立,都会至少执行一次循环。
需求: 实现 10 次 “Hello World!!” 的控制台输出

var i = 0;
do {
    console.log("Hello World!!");
    i++;
} while (i < 10);

解析:

  • 1.当 i=0 时,打印第 1 次 “Hello World!!” 打印完成 i 自增变成 1;
  • 2.改变后的 i = 1 去和 10 做对比 i = 1 < 10 成立,条件成立,继续执行循环体 打印第 2 次 “Hello World!!” 打印完成 i 自增变成 2 ;
  • 3.改变后的 i = 2 去和 10 做对比 i = 2 < 10 成立,条件成立,继续执行循环体 打印第 3 次 “Hello World!!” 打印完成 i 自增变成 3;
  • 4…
  • 5.改变后的 i = 9 去和10 做对比 i = 9 < 10 成立,条件成立,继续执行循环体 打印第10次"Hello World!!" 打印完成 i 自增变成 10;
  • 6 改变后的 i = 10 去和10做对比 i = 9 == 10 成立,条件不成立,跳出循环

练习: 输出 1-100 之间,可以同时被 3 和 7 整除的整数(do…while 实现)

var i = 1;
do {
    // 通过条件语句判断,循环到的  i 的值是否能被 3 和 7 同时整除
    if (i % 3 == 0 && i % 7 == 0) {
        console.log(i, "能被 3  和 7 同时整除");
    }
    i++;
} while (i <= 100);
console.log("i:", i); // i:101

(3) for 循环

语法格式:
for(初始化变量;条件表达式;变量操作){循环体}

执行步骤:

  • 初始化变量
  • 判断条件表达式是否成立
  • 条件表达式成立的情况下,执行循环体
  • 变量的操作
  • 继续执行第 2、3、4步,直到第2步中的条件表达式不成立为止,跳出循环

练习: 在控制台输出 10 次 “Hello world!”

// while 循环向 for 循环的演变

// 初始化变量
var i = 0;
// while 循环
while (i < 10) {
    // 条件表达式
    // 大括号包裹的,也叫循环语句
    console.log("Hello World!!");
    i++;
}

// 初始化值
var i = 0;
// for 循环
for(var i=0;i<10;i++){
    console.log("Hello World!!!");
}

(4) 穷举思想

概述: 我们镜像想要得到一组数据,这些数据有特定的场景要求,计算机没有办法帮我们输出这些数据。我们需要人为的去编写一段程序,来实现这个功能:将所有可能符合要求数据一一列举出来,然后人为设置限制条件,将符合条件的数据筛选出来,不满足的跳过,继续验证下一个可能符合要求的数据,直到把所有可能的数据都验证一遍,这个方法叫做穷举法,穷举法也叫全举法
将可能符合要求的数据,使用 for 循环进行一一列举(遍历);
在 for 循环的内部,使用 if 条件语句对这些可能符合条件的数据,进行一一验证,筛选出真正的符合条件的数据.

代码演示: 提示用户输入一个大于0 的整数,在控制台输出这个数字所有的约数

var num = Number(prompt("请输入一个大于 0 的整数", "10"));

// 按照穷举思想,先把所有可能的数据列举出来:一个数的约数,最小是1,最大是它本身
for (var i = 0; i <= num; i++) {
    // console.log("i:",i);
    // 按照约数的定义规则,判断是否是输出的这个数字的约数,
    // 判断条件:遍历的这个数字 i 可以整除用户输入的数组 num
    if (num % i == 0) {
        // 取余的结果为 0 ,即是其约数
        console.log(i, "是", num, "的约数");
    }
}

(5) for 循环嵌套

for 嵌套循环,说白了就是 for 循环里面嵌套 for 循环
在页面文档中输出数据的方式: document.write(“内容”)

练习: 在页面中输出 “九九乘法表”

    <style>
        table{
            border-collapse: collapse;
        }
        td{
            padding: 4px 8px;
            border: solid 1px;
        }
    </style>
</head>

<body>
    <script>
        document.write("<table>")
        for (var i = 0; i <= 9; i++) {
            document.write("<tr>")
            for (var j = 1; j <=i; j++) {
                document.write("<td>")
                document.write(j + "&times;" + i + "=" + (i * j))
                document.write("</td>")
            }
            document.write("</tr>")
        }
        document.write("</table>")
    </script>
</body>

(6) 综合小练习

输出 100 - 999 之间的水仙花数(水仙花数值的是每个数值位上的数值的立方和等于当前数字)
如: 153 = 1³ + 5³ + 3³

// 穷举思想第一步: 一一列举出所有可能的值
for (var i = 100; i < 1000; i++) {
    // 声明三个变量:接收百位数字的 b 接收十位数字的 s  接收个位数字的 g
    var b = parseInt(i / 100);
    var s = parseInt(i % 100 / 10);
    var g = parseInt(i % 10);

    // 穷举思想的第二步 通过设置条件,从可能的值中筛选出确定符合条件的值
    if (Math.pow(b, 3) + Math.pow(s, 3) + Math.pow(g, 3) == i) {
        console.log(i, "是水仙花数");
    }
}

// 153 '是水仙花数'
// 370 '是水仙花数'
// 371 '是水仙花数'
// 407 '是水仙花数'

(7) 累加法

求:1 + 2 + 3 + 5 + … + 99 + 100 的和

// 累加需要将每一次遍历到的数值都加到之前遍历的数字和之上,并保留最新改变后的和
// 所以这里,声明一个变量,来保存每一次累加后的和
var sum = 0;
for (var i = 1; i <= 100; i++) {
    // 等价于 sum = sum + i
    sum += i;
}
// 循环完成,将累加的结果输出
console.log("sum", sum); // sum 5050

(8) 累乘法

求 1 * 2 * 3 * 4 * 5 的积

var sum = 1;
for (var i = 1; i <= 5; i++) {
    sum *= i;
}
console.log("sum:", sum);// sum:120

十四、控制语句

一般情况下,我们在执行循环时,只要是满足循环条件,那么循环体就会一直执行下去
这个时候,我们想要在循环时,达到某种条件时,控制循环的执行,那么就用到控制语句
控制语句有两个: break 和 continue

  • break 打断、中断 在 JS 中可以应用于 switch 语句、循环语句(常见于for循环),用来跳出语句或者说是结束语句的执行

练习: 遍历 1-10 之间的数字,当数字是 6 的时候,跳出循环,打印结果: 1,2,3,4,5,

for (var i = 1; i <= 10; i++) {
    if (i == 6) {
        break;
    }
    console.log("i:", i);
}
console.log("循环执行完毕i", i);
// i:1   i:2  i:3  i:4  i:5 循环执行完毕 i: 6
  • continum 继续 在 js 中,一般应用于循环语句中,用来跳过本次循环继续下一次循环
    需求: 遍历 1-10 之间的数字,当数字是 6 的时候,跳过本次循环继续下一次循环
    打印结果:1,2,3,4,5,7,8,9,10
for (var i = 0; i <= 10; i++) {
    if (i == 6) {
        continue;// 跳过本次循环继续下一次循环
    }
    console.log("i:", i);
}
console.log("循环执行完毕 i", i); // 循环执行完毕 i 11
  • 多层嵌套循环下,跳出或跳过指定循环
outter: for (var i = 1; i <= 5; i++) {
    inner: for (var j = 1; j <= 5; j++) {
        if (j == 3) {
            // break;// 跳出当前循环,当前循环为内层循环
            // continue;// 跳过本次循环继续下一次条件循环

            // break outter;// 跳出指定标记的那一层循环
            continue outter;

        }
        console.log("i:", i, "j:", j);
    }
}

十五、函数的声明于调用

(1) 函数的概述

函数可以封装一些功能,可以供外部去重复的调用。所以,一般我们把函数叫做具有重复功能的代码块。

(2) 函数的声明

函数使用关键字 function 来进行声明
在声明的函数内部,可以写一些代码,使这个函数具有某一种特定的功能。在函数内部书写的代码习惯上称为函数体
函数声明的语法格式

function 函数名(形式参数){
    函数体
}
// 思考: 求任意两个数的和
var a = 10, b = 20;
console.log(a + b); // 30

var i = 100, j = 200;
console.log(i + j); // 300

// 假设:还有很多数字,那么都要去执行求和操作,那样需要声明好多变量,且功能(求和操作)重复的,这个时候我们就可以借助函数进行优化
// 函数是具有重复功能的代码块
function sum(num1,num2){
    // return 返回的意思  这里用来返回数据
    return num1 + num2;
}
console.log(sum(10,20)); // 30
console.log(sum(100,200)); // 300

函数名的命名规则:同变量名规则

(3) 函数的调用

函数声明后,不会自动执行,需要进行调用
函数调用的语法 函数名()
函数的调用方式

  • 直接在 JS 脚本的任意位置进行调用 函数名()
  • 事件驱动

练习: 使用函数包装流程语句,也就是将流程语句当作函数体。一个大于 0 的 整数,打印它所有的约数.
分析: 一个数它的最小约数是1,最大约数是它本身。 如果还有其它的约数,肯定在 1 和 它本身之间
什么是约数?
约数,又称因数,整数a除以整数b(b≠0)除的商正好是整数而没有余数,我们就说a能被b整除,或 b 能整除a,a称为b 的倍数,b 称为a 的约数

// 提示用户输入一个大于 0 的整数
var num = parseInt(prompt("请输入一个大于 0 的整数", "20"));

// 不使用函数
// 使用 for 循环一一列举可能的值
// for (var i = 1; i <= num; i++) {
//     // 通过 if 指定约数条件
//     if (num % i === 0) {
//         console.log(i, "是", num, "的约数");
//     }
// }
// console.log(i);

// 函数封装
getYs(num)
function getYs(n) {
    for (var i = 0; i <= n; i++) {
        if (n % i === 0) {
            console.log(i, "是", n, "的约数");
        }
    }
}
// console.log("i:", i); // 报错

使用函数封装简单介绍几个好处

  • 避免全局变量的污染
  • 节约内存
  • 提高程序的执行效果
  • 减少重复代码的书写
  • 便于后期维护
  • 可以返回数据进行二次操作

(4) 函数的类型

function f(){}
console.log(typeof f); // function

十六、函数的参数

(1)函数参数概念

参数可以类似的看作我们之前声明的变量,只不过它的位置在函数后面的小括号中,且不需要再使用 var 进行声明,函数的参数分为两种:形式参数实际参数
形式参数: 简称形参 在函数声明的时候,小括号中给定的参数,此时,不能确定参数的数据类型 和 具体的值。
实际参数: 简称实参 . 在函数调用的时候,用来替换形参的具体的值(传递的参数),此时确定了数据类型和值

传参: 函数调用,有一个传递参数的过程,这个过程叫做传参

需求: 求一个大于0的整数,约数的个数

// 需求: 求一个大于 0 的整数,约数的个数
var num = parseInt(prompt("请输入一个大于 0 的整数", "20"));

// 封装一个函数,实现求一个数约数的个数
function getYsCon(n) {
    // 声明一个变量,来接收每一次符合是约数后,递增的个数
    var count = 0;
    // 一一获取可能是约数的值
    for (var i = 0; i <= n; i++) {
        // 判断可能的值是否真的是需要的约数
        // 条件成立,即是约数
        if (n % i === 0) {
            count++
        }
    }
    // 将 count 符合条件的个数 返回
    return count;
}
console.log(getYsCon(num));// 6

js 是一门动态的、弱类型语言

(2) 函数的重载

重载可以看作是函数参数的应用
函数的重载: 在一个程序中,声明多个同名的函数,但是其数据类型以及参数的个数并不相同。JS 中不存在函数重载的概念,只能模拟,因为一旦在 js 中声明多个同名函数,后面的会覆盖前面的

// 三个数的和
function sum(a, b, c) {
    console.log("a:", a, "b:", b, "c:", c);
    console.log(arguments);
    return a + b + c;
}

// 函数调用
console.log(sum(10,20)); // NaN 
console.log(sum(10,20,30)); // 60 
console.log(sum(10,20,30,40)); // 60  直接匹配对应参数的个数,多余的砍掉

JS 中不存在函数重载的概念,只能模拟。因为一旦在 JS 中声明多个同名函数,后面的会覆盖前面的。

总结:

  • 实参的数量少于形参,结果肯定是 NaN
  • 实参的数量多余形参,结果是取匹配形参数量的实参,去执行得到相应的结果,砍掉多余的参数

但是,可以通过 arguments 对象实现重载的模拟

(3) arguments 对象

arguments 对象是 JS 中一个特殊的对象,它是一个类数组,存储的是函数调用时所传递的实际参数
arguments 对象中内置了一个 length 属性,用来获取函数调用时实际传递的参数的个数
语法: arguments.length
类数组和数组都具有索引,索引从 0 开始,依次递增,如上图: arguments 对象中,有对应的索引,一一对应于传递的参数,通过 **arguments[索引] ** 可以获取执行的对应的参数值
获取第一个参数 arguments[0]
获取最后一个参数 arguments[arguments.length - 1]

function sum() {
    console.log("arguments", arguments);  // arguments Arguments(3) [10, 20, 30, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    console.log("函数调用时传递的第一个参数:", arguments[0]); // 10
    console.log("函数调用时传递的参数个数", arguments.length); // 3
    console.log("函数调用时传递的最后一个参数", arguments[arguments.length - 1]); // 30
}

sum(10,20,30)

模拟函数的重载,这个地方做一个求和操作

function sum(){
    // 声明一个变量,来存储每次累加的结果
    var result = 0;

    // 遍历 arguments 对象的索引
    for(var i = 0; i<arguments.length;i++){
        result += arguments[i]
    }
    return result;
}

console.log(sum(10,20,30)); // 60

十七、函数的返回值

很多情况下,我们封装函数的目的是为了利用函数的这个功能,得到某些数据,然后对这些数据进行二次操作。
那么,如果想要在函数中返回这些数据,那么需要用到关键字 return
return 关键字用于在函数中返回数据,并跳出函数
如果仅仅是为了跳出函数,而不需要返回任何数据,那么直接 return 即可

练习:判断一个大于0 的数字是否是质数
什么是质数?
质数也叫素数,是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数.
分析: 可以根据约数的个数,当约数的个数是 2 的时候,那么这个数就是质数

var sum = parseInt(prompt("请输入一个整数", "30"))

// 第一种方式
// console.log(isZh(sum));
// // 封装一个函数,判断一个数字是否是质数
// function isZh(num) {
//     var count = 0;
//     for (var i = 0; i <= num; i++) {
//         if (num % i === 0) {
//             count++;
//         }
//     }

//     // 判断 count 的数量
//     if (count === 2) {
//         return num + " 是质数"
//     } else {
//         return num + " 不是质数"
//     }
// }


// 第二种方式 将上面的方式进行改造
// 改造,使函数具有单一独立的功能
// 封装一个函数,获取一个数约数的个数

function YsCount(num) {
    var count = 0;
    for (var i = 0; i <= num; i++) {
        if (num % i === 0) {
            count++
        }
    }
    // 返回约数的个数
    return count;
}

// 封装一个函数,判断一个数字是否是质数
function ZsCount(num) {
    // 判断 count 的数量
    if (YsCount(num) == 2) {
        return num + " 是质数"
    } else {
        return num + " 不是质数"
    }
}

console.log(ZsCount(sum));
// 上面单一功能模块函数: 功能尽量单一、降低耦合性、提高代码的可复用性

return 作为跳出函数用

return 、break、continue 的区别?

function fn() {
    for (var i = 1; i <= 5; i++) {
        if (i == 3) {
            // continue;// 跳过本次循环继续下一次循环
            // break;// 跳出当前循环
            return;// 跳出函数用
        }
        console.log(i);
    }
    console.log("循环外,函数中");
}
fn()

十八、函数的作用域

(1) 作用域概述

概述: 当声明函数后,在函数的内部(大括号函数体位置) 形成自己一个独立的内部区域,这个内部区域就叫做函数作用域

函数作用域相对于整个脚本区域来讲,只是一个很小的独立区域,这个很小的区域我们通常叫它局部作用域。而整个脚本区域,通常叫做全局作用域。

全局作用域: 函数外的区域叫做全局作用域;在全局作用域种声明的变量,可以在脚本的任何位置(包裹函数内) 都可以对其进行调用,这个变量我们称之为全局变量。全局变量的生命周期:从文件被执行时创建(当前就是页面被加载),页面关闭后销毁

局部作用域:函数内的区域叫做局部作用域;在局部作用域中声明的变量,只能在函数的内部进行访问调用,那么此时我们称其为局部变量。 局部变量的生命周期:函数被调用时创建,函数调用完毕销毁

// 全局变量:可以在页面的任何位置被调用
var num = 10;
console.log("num:",num); // num:10

fn();// 声明的函数只有被调用,才会执行
function fn(){
    console.log("num:",num); // num:10
}


// 局部变量:只能在当前作用域内被调用
fn2();
function fn2(){
    var n = 100;
    console.log("n:",n); // n:100
}
// console.log("n:",n); // n is not defined

fn3()
function fn3(){
    console.log("n:",n); // n is not defined
}

(2) 作用域链的问题

嵌套函数中,存在多个被声明的同名函数,在调用时,首先查看当前作用域是否有这个变量,有则调用,没有则去它的上一级作用域中查找,如果有则使用。如果没有,继续向上查找,直到找到为止

// 声明一个全局变量  num
var num = 1;
function fn(){
    // 在第一层函数中,声明一个变量  num
    var num = 10;
    // 在第一层函数中,声明一个内部函数  fn2
    // 创建函数的另外一个方式  将声明的匿名函数赋值给一个变量
    var fn2 = function(){
        var num = 100;
        return num;
    }
    return fn2;
}

console.log(fn()); // 返回 f() 函数体
console.log(fn()()); // 100

(3) 局部作用域内不使用 var 声明的变量

如果在函数的内部,不使用 var 声明,首先这是不标准的写法,一般不建议,且在严格模式下会报错.其次,如果我们不小心这样用了,那么在函数被调用后,这个变量会提升为全局变量。如果函数没有被调用,则不会创建这个变量

function f(){
    num = 10;
    console.log("num:",num);
}

这种情况,很容易造成全局变量的污染,不建议使用

var i = 2;
console.log("i:", i);

function f1() {
    var i = 20;
    console.log("i:", i); // i: 20 
}
f1();
console.log("i:", i); // i:2

var j = 3;
console.log("j:", j); // j: 3
function f2() {
    j = 30;
    console.log("j:", j); // j:30
}
f2();
console.log("j:", j);//j:30

上面的本身是想作为一个局部变量来处理,但是由于没有使用 var 声明,造成函数调用时,这个本要作为局部变量定义的变量变成了全局变量的赋值操作,这样就造成了全局变量的污染或称为命名冲突

(4) 同一个变量多次声明

如果在同一个作用域内,一个变量被多次声明,那么声明只会生效一次,以第一次声明为准,后面的声明不再作数,直接作为变量的赋值操作

var num = 1;
console.log("num:",num);// num:1

var num = 10;
console.log("num:",num); // num:10 

num = 100;
console.log("num:",num); // num:100

十九、函数的提升

在 JS 中,有变量和函数的提升,JS 引擎在解析代码时,分成两步:

  • 1.预解析阶段:将所有变量 和 函数的声明,提升到当前作用域的最顶部
  • 2.运行阶段: 进行变量的赋值操作
    在 JS 中,函数的创建方式有三种:
  • 第一种 标准的方式 function 函数名(参数列表){函数体}
function f() {
    num = 10;
    return "num:" + num
}
console.log(f()); // num: 10 
  • 第二种函数表达式的方式:将一个匿名函数赋值给一个变量 var f = function(参数列表){函数体}
var f1 = function () {
    num = 10;
    return "num:" + num
}
console.log(f1()); // num:10
  • 第三种内置对象的方式 var f = new Function(“参数列表”,“函数体”)
var f3 = new Function("num=20;return 'num:' + num");
console.log(f3()); // num:20

var f2 = new Function("a","b","return a+b");
console.log(f2(10,20)); // 30 

使用标准的方式创建的函数,与其他两种方式调用时的不同:

  • 如果都是先声明,再去调用,看不出有什么区别:
  • 如果事先调用,再去声明的情况,结果就不同了,如下:
    非标准的方式,利用的是一个变量来接收一个函数,那么其本质就是变量。变量的提升,相当于将变量的声明提升到当前作用域的最顶部,这时还没有赋值,在调用的时候,变脸的值是 undefined,所以后面两种创建函数的方式,只能先声明再调用
    标准的方式:会将整体作为一个声明部分,在预解析阶段,将其整体提升到当前作用域的最顶部,所以标准的方式创建的函数可以在当前作用域的任何位置被调用
// 第一种 标准的方式  function  函数名(参数列表){函数体}

console.log("f()", f()); // f(): num :10 
function f() {
    num = 10;
    return "num:" + num
}
console.log("f():", f()); // f(): num:10


// 第二种函数表达式的方式,将一个匿名函数赋值给一个变量  var  f = function(参数列表){函数体}
console.log("f1:", f1);// f1:undefined

// console.log("f1()", f1()); // f1 is not a function

var f1 = function () {
    num = 10;
    return "num:" + num;
}

console.log("f1()", f1()); // f1() num:10

小问题: 如果在同一个文件中,存在同名的变量和函数,函数优先于变量的提升,声明多个变量,只有一个会生效,而函数也可以看作是变量,不管是使用 var 还是使用 function 都叫做声明。所以函数优先于变量提升后,其他变量的声明都变成了赋值操作

// 变量 和 函数冲突,函数优先于变量提升
// console.log("f1:", f);
// var f = 1;
// console.log("f2:", f);

// function f() {
//     console.log("f3:", f);
// }
// f();


// 等价于
function f() {
    console.log("f:", f);
}
console.log("f:", f);

var f = 1;
console.log("f:", f);
f();

在这里插入图片描述

二十、模块化编程

案例: 输出 100 以内的质数,模块化编程

逆向思维的过程: 输出 100 以内的质数 —> 判断是不是质数 —> 找约数的个数

// 声明一个函数,来输出指定大于 0 的整数以内所有的质数
getAllzs(100);
function getAllzs(num) {
    // 一一列举可能的值 
    for (var i = 0; i <= num; i++) {
        if (isZs(i)) {
            console.log(i + " 是质数");
        }
    }
}

// 声明一个函数,判断一个数是不是质数
function isZs(num) {
    // 如果约数的个数是2,也就是只有1 和 本身两个约数的情况,那么这个数就是质数
    if (getYsCount(num) === 2) {
        return true;
    } else {
        return false
    }
}

// 声明一个函数,获取一个数约数的个数
function getYsCount(num) {
    var count = 0;
    for (var i = 0; i <= num; i++) {
        if (num % i == 0) {
            count++
        }
    }
    return count;
}

二十一、数据类型在内存中的位置

数据类型有两大类:基本数据类型引用数据类型

  • 基本数据类型: Number 数值类型 String 字符串类型 Boolean 布尔类型 Null 空类型 Undefined 未被定义的
  • 引用数据类型: Object 对象类型 Function 函数类型

基本数据类型存储在内存的栈中,引用数据类型存储在堆中

内存分区如下:
在这里插入图片描述

var a = 10, b = 20, c = 30, fn = function () { };
console.log("a:", a, "b:", b, "c:", c, "fn:", fn);
// a: 10 b: 20 c: 30 fn: ƒ () { }

// 修改 b 的值
b = 200;
console.log("a:", a, "b:", b, "c:", c, "fn:", fn);
// a: 10 b: 200 c: 30 fn: ƒ () { }

// 声明一个变量 d 来接收基本数据类型的变量 c
var d = c;
console.log("c:", c, "d:", d);// c: 30 d: 30


// 改变基本数据类型 c 的值
c = 300;
console.log("c:", c, "d:", d); // c: 300 d: 30
// 总结:基本数据类型变量在进行赋值时,只是将变量保存的值复制了一份给另外一个变量进行赋值。
// 此时变量值的改变不会相互影响


// 声明一个变量,来接收引用数据类型的变量
var fn2 = fn;
console.log("fn:", fn, "fn2:", fn2);//fn: ƒ () { } fn2: ƒ () { } 
console.log(fn === fn2); //true  指向同一个内存地址

// 改变其中一个引用数据类型的结构
fn.x = 100;
console.log("fn:", fn, "fn2:", fn2); //fn: ƒ () { } fn2: ƒ () { }
console.log(fn === fn2); // true 指向同一个内存地址
console.log("fn.x", fn.x, "fn2.x", fn2.x); //fn.x 100 fn2.x 100
// 总结:引用数据类型变量在进行赋值时,将引用数据类型的变量保存的地址复制了一份给另外一个变量复制。
// 此时两个变量指向同一个地址,其中一个结构发生改变会影响另外一个
  • 总结:基本数据类型变量在进行赋值时,只是将变量保存的值复制了一份给另外一个变量进行赋值。此时变量值的改变不会相互影响
  • 总结:引用数据类型变量在进行赋值时,将引用数据类型的变量保存的地址复制了一份给另外一个变量复制。此时两个变量指向同一个地址,其中一个结构发生改变会影响另外一个

二十二、递归函数

递归就是在函数的内部调用函数自己本身;
递归函数多用来解决一些数字0以上的数学问题
递归函数必须给定一个条件,来退出函数,否则会造成内存堆栈溢出的问题
如:

  • 累加问题 1 + 2 + 3 + … + 98 + 99 + 100
  • 累乘问题 100! = 100 * 99 * 98 * … * 3 *2 * 1

生兔子的问题 有一对兔子,三个月开始每个月生一对小兔子,这一对小兔子在成长到三个月的时候每个月也是生一对小兔子,问一年之后,在没有死亡的情况下,总共有多少对兔子

换算成数学,就是一个斐波那契数列 1 1 2 3 5 8 13 21 34 55 89 144

// 斐波那契数列  1  1  2  3  5  8  13  21  34  55  89  144...

console.log(feiBo(12)); // 144


// 求斐波那契数列中第 N 项的值
function feiBo(n) {
    if (n === 1 || n === 2) {
        return 1;
    }
    return feiBo(n - 1) + feiBo(n - 2)
}

// feiBo(3) = feiBo(3 - 1) + feiBo(3 - 2) = feiBo(2) + feiBo(1) = 1 + 1 = 2
// feiBo(4) = feiBo(4 - 1) + feiBo(4 - 2) = feiBo(3) + feiBo(2) = feiBo(3 - 1) + feiBo(3 - 2) + 1 = 1 + 1 + 1 = 3
// feiBo(5) = ....

二十三、匿名函数和自执行函数

匿名函数: 也叫拉姆达函数,说白了就是没有名字的函数
自执行函数: IIFE ,也叫立即执行函数。不需要进行调用,随着程序的执行会自动调用。IIFE 有两部分组成,函数体和执行部分

// 匿名函数的使用
// 1 声明一个变量,来接收一个匿名函数
// var f = function () {

// };

// 事件驱动  window 窗口对象的点击事件
var count = 0;
window.onclick = function () {
    console.log("第" + (++count) + "次点击了窗口...");
}

// IIFE 自执行函数
; (function (a, b) {
    console.log(a + b);
})(10, 20);

var result = (function (a, b) {
    return a + b;
})(10, 20)
console.log("result", result);

二十四、什么是闭包

闭包就是一个函数可以访问另外一个函数内部的变量
想要理解闭包,需要先了解 作用域链的问题 和 垃圾回收机制的问题(设置到变量的生命周期)
在 js 中,任何一个函数都可以认为是闭包;常见的情况是,函数中可以访问全局变量,嵌套函数可以访问祖先元素中的变量

function f() {
    var i = 1;
    function f2() {
        console.log(i);
    }
    return f2;
}

// f 函数中的变量 i 是一个局部变量,局部变量只能在函数的内部被访问到
function f3() {
    console.log(i);  // 报错
}

如果想要在一个函数的外部,访问这个函数内部的变量,需要进行
假设,将嵌套在内部的函数作为一个联通内外的桥梁,在调用外层函数时,返回这个内部的函数

function f(){
    var i = 1;
    return function (){
        return i++;
    }
}

console.log(f); // 返回整体函数
console.log(f()); // 返回内部函数
console.log(f()()); // 1
console.log(f()()); // 1
// 也就证明,每一次都是一个全新的环境,得到的值也是一样
// 局部变量和函数在外部函数调用完毕后即销毁

// 那么.利用对象之间的引用关系,可以保存当时执行的一个环境,进而将局部的变量保存下来
// 垃圾回收机制中,对存在引用关系的对象不会进行回收
var test = f();// 此时 test 就是一个函数
console.log(test); // 返回内部函数
console.log(test()); // 1
console.log(test()); // 2
console.log(test()); // 3


var test2 = f();
// 此时又是一个新的闭包函数  当执行 f()  时,传递给 test2 的那个桥梁函数会记住当时所执行的上下文环境
console.log(test2); // 返回内部函数
console.log(test2());// 1
console.log(test2());// 2

闭包的问题:

闭包不宜使用过多,容易造成内存的泄露问题;

但是,使用闭包可以避免全局变量的污染,很多高级程序中,都会有闭包的应用。
利用闭包来私有化对象的属性和方法;

利用闭包目前可以用来解决: 循环中,有异步语句存在的情况下,无法正确获取索引的问题\

console.log(11111);

// 回调函数:将一个函数作为另外一个函数的参数
// 在 JS 中,有一个内置的延迟器,在指定时间后,去执行相应的操作
setTimeout(function () {
    console.log(22222);
})
console.log(33333);

// 循环中,异步语句,获取索引的问题
for (var i = 0; i < 10; i++) {
    console.log("i:", i);
}

for (var i = 0; i < 10; i++) {
    (function (j) {
        setTimeout(function () {
            console.log("内j:", j);
        })
    })(i)
}
console.log("外i",i);

二十五、数组对象

数组对象是 JS 中的一个内置对象,其内置了很多方法和属性供我们使用
想要理解数组对象,先要理解什么是数组?
变量是用来存储信息的容器,但是一个变量只能存储一条信息。而数组,可以看作是存储多条信息的容器,其存储的数据可以是任意数据类型
数组是由中括号进行包裹,存储的数据之间使用逗号隔开,如

var arr = [10, "hello", true, null, undefined, Math.random(), function(){}, new Object()];
console.log("arr:",arr);
// arr: (8) [10, 'hello', true, null, undefined, 0.5265404143120307, ƒ, {…}]

数组是一系列数组的集合,所以数据是有长度的,通过 length 属性可以获取数组中元素的个数.
数组具有索引,索引从 0 开始,依次递增,最大的索引值 arr.length -1。
通过索引可以获取其在数组中对应的值,如:
数组中的第一个值 arr[0]
数组中的最后一个值 arr[arr.length -1]
通过指定索引不仅可以获取值,还可以用来对值进行修改操作。

(1) 数组对象的创建方式

  • 字面量的方式 var arr = [10,20,30,40,50,60];
var arr = [10, 20, 30, 40, 50, 60];
console.log("arr", arr);
// arr (6) [10, 20, 30, 40, 50, 60]


// 通过索引获取值
console.log("数组 arr 中第一个元素是:", arr[0]);
// 数组 arr 中第一个元素是: 10
console.log("数组 arr 中元素的个数", arr.length);
// 数组 arr 中元素的个数 6
console.log("数组 arr 中最后一个元素是", arr[arr.length - 1]);
// 数组 arr 中最后一个元素是 60


// 通过索引值修改
arr[2] = 300;
console.log("arr",arr);
// arr (6) [10, 20, 300, 40, 50, 60]


// 通过索引添加值
arr[6]=70;
console.log("arr:",arr);
// arr: (7) [10, 20, 300, 40, 50, 60, 70]
  • 通过 new 关键字 var arr = new Array();
    • 如果 new Array(arg) 中的参数 arg 只是一个数值类型的整数,那么代表的是数组的长度
    • 如果 上面参数 arg 是其它数据类型,或者是多个参数,那么代表的是数组中的元素
var  array = new  Array();
console.log("array",array); 
// array [] 这是一个空数组

array = new Array(10);
console.log("array",array);
// array (10) [empty × 10]  这是一个长度为 10 的数组,但是数组中没有值

// 通过索引添加值
array[0] = 100;
array[1] = 200;
array[8] = 900;
array[9] = 1000;
array[14] = 1400;

console.log("array:",array);
// array: (15) [100, 200, empty × 6, 900, 1000, empty × 4, 1400]

array = new Array("10");
console.log("array",array); //array ['10']

// array = new Array(3.14);
// console.log("array",array); //Invalid array length

array = new Array(10,20);
console.log("array",array); // array (2) [10, 20]

(2) 数组中的属性

length 属性用于获取数组中元素的个数

constructor 获取数组对象的构造函数

构造函数和普通函数,最明显的区别就是构造函数的首字母大写

var arr = [10,20,30,40];
console.log("arr:",arr,"数据类型:",typeof arr);
// arr: (4) [10, 20, 30, 40] 数据类型: object

// length  获取数组中元素的个数
console.log("数组中元素的个数:",arr.length);
// 数组中元素的个数: 4

// constructor  获取指定对象构造函数
console.log("数组的构造函数:",arr.constructor);
// 数组的构造函数: ƒ Array() { [native code] }

(3) 数组中的方法

① 数组转字符串的方法

  • toString() 将数组对象转换成字符串对象
    • 这个方法没有参数
    • 返回值是一个字符串
  • join(seperator?) 将数组对象按照指定的分隔符转换成字符串对象
    • 参数 seperator 可选参数。指定分隔符号,是一个字符串类型
    • 返回值是一个字符串
var arr = [10, 20, 30, 40, 50, 60];
console.log("arr", arr, "数据类型:", typeof arr);
// arr (6) [10, 20, 30, 40, 50, 60] 数据类型: object

// toString() 将数组对象转换成字符串的方法
var str = arr.toString();
console.log("str", str, "数据类型:", typeof str);
// str 10,20,30,40,50,60 数据类型: string

// join(seperator?)  将数组对象按照指定的分隔符转换成字符串对象
var str2 = arr.join();
console.log("str2", str2, "数据类型", typeof str2);
// str2 10,20,30,40,50,60 数据类型 string

str2 = arr.join("&");
console.log("str2",str2,"数据类型:",typeof str2);
// str2 10&20&30&40&50&60 数据类型: string

② 数组首尾操作的方法

  • push(args…) 向数组的末尾追加一个或多个元素

  • unshift(args…) 向数组的起始位置追加一个或多个元素

    • 参数 args 要向数组中添加的数据,可以是任意数据类型
    • 返回值 添加数据后,新的数组长度
      这两个方法,都使原数组结构发生了改变
  • pop() 删除数组中的最后一项

  • shift() 删除数组中的第一项

    • 这两个方法没有参数
    • 返回值 返回删除的那一项元素
var arr = ["橘子","橙子","苹果","菠萝"];
console.log("arr:",arr);

// push(args...)  向数组末尾追加一个或者多个元素
var len = arr.push("哈密瓜","火龙果"); // arr: (4) ['橘子', '橙子', '苹果', '菠萝']
console.log("arr:",arr); // arr: (6) ['橘子', '橙子', '苹果', '菠萝', '哈密瓜', '火龙果']
console.log("len:",len); // 返回的是数组的长度     len: 6


// unshift(args...)  向数组开始追加一个或多个元素
var len2 = arr.unshift("红富士","提子");
console.log("arr:",arr); // arr: (8) ['红富士', '提子', '橘子', '橙子', '苹果', '菠萝', '哈密瓜', '火龙果']
console.log("len2",len2);  // 返回的是数组的长度  len2 8   

// pop()   删除数组中最后一项
var tipEle = arr.pop();
console.log("返回的 arr",arr); 
// 返回的 arr (7) ['红富士', '提子', '橘子', '橙子', '苹果', '菠萝', '哈密瓜']
console.log("tipEle 删除的元素是:",tipEle); 
// tipEle 删除的元素是: 火龙果 


// shift()  删除数组中的第一项
var headEle = arr.shift();
console.log("返回的 arr",arr);
// 返回的 arr (6) ['提子', '橘子', '橙子', '苹果', '菠萝', '哈密瓜'] 
console.log("headEle 删除的元素是:",headEle);
// headEle 删除的元素是: 红富士

③ 插入、删除、替换 的方法

  • splice(startIndex,delCount,addEles…) 在指定索引处,删除指定数量的元素,并追加新的元素
    • 参数 startIndex 插入或删除元素的起始索引
    • delCount 指定索引处删除的元素的个数
    • addEles… 指定索引处插入一个或多个元素
      返回值 返回的是删除的元素组成的数组
var arr = [10, 20, 30, 40, 50, 60];
console.log("arr", arr); // arr (6) [10, 20, 30, 40, 50, 60]

// splice(startIndex,delCounr,addEles...)
// 在指定索引处,删除指定数量的元素,并追加新的元素

var delEles = arr.splice();
console.log("arr", arr); // arr (6) [10, 20, 30, 40, 50, 60] 
console.log("delEles", delEles); // delEles [] 

delEles = arr.splice(4);
console.log("arr", arr); // arr (4) [10, 20, 30, 40] 
console.log("delEles 删除索引 4 后面的元素", delEles);
// delEles 删除索引 4 后面的元素 (2) [50, 60]

delEles = arr.splice(2, 1);
console.log("arr", arr); // arr (3) [10, 20, 40] 
console.log("delEles 删除位置索引为 2 的一个元素", delEles);
// delEles 删除位置索引为 2 的一个元素 [30] 


delEles = arr.splice(1, 0, 300, 400, 500, 600, 800);
console.log("arr:", arr); //  arr: (8) [10, 300, 400, 500, 600, 800, 20, 40]
console.log("delEles", delEles);  delEles []

④ 数组拼接 和 数组片段的截取

  • concat(args) 拼接一个或多个元素或数组
    • 参数 args 拼接的元素或数组
    • 返回值是拼接后的新数组
  • slice(startIndex,endIndex) 截取指定索引之间的元素
    • 参数 startIndex 截取数组的起始索引
    • endIndex 截取数组的结束索引
    • 返回值是 截取的元素组成的新数组

上面两个方法,不会改变原数组

var arr = ["苹果", "香蕉", "橘子", "火龙果", "猕猴桃"];
console.log("原数组arr:", arr);
// 原数组arr: (5) ['苹果', '香蕉', '橘子', '火龙果', '猕猴桃']


// cancat(args)  拼接一个或多个元素或数组
var newArr = arr.concat("橙子", "柚子", ["西瓜", "菠萝"]);
console.log("拼接后 arr", arr);
// 拼接后 arr (5) ['苹果', '香蕉', '橘子', '火龙果', '猕猴桃']
console.log("拼接后返回的数组 newArr", newArr);
// 拼接后返回的数组 newArr (9) ['苹果', '香蕉', '橘子', '火龙果', '猕猴桃', '橙子', '柚子', '西瓜', '菠萝']


// slice(startIndex,endIndex)  截取指定索引之间的元素
// 指定一个起始索引,一直截取到最后
var sliceArr = newArr.slice(6);
console.log("返回的原数组 arr", arr);
// 返回的原数组 arr (5) ['苹果', '香蕉', '橘子', '火龙果', '猕猴桃']
console.log("截取的数组 sliceArr", sliceArr);
// 截取的数组 sliceArr (3) ['柚子', '西瓜', '菠萝']


// 指定两个参数: 截取两个索引之间的数组片段  左闭右开
sliceArr = newArr.slice(3, 6);
console.log("返回的原数组 arr",arr);
// 返回的原数组 arr (5) ['苹果', '香蕉', '橘子', '火龙果', '猕猴桃'] 
console.log("截取的数组", sliceArr);\
// 截取的数组 (3) ['火龙果', '猕猴桃', '橙子']

⑤ 倒叙 和 排序

  • reverse() 对数组中的元素进行倒叙排列;没有参数
  • sort(callbackfn) 对数组中的元素进行排序
    • 参数 callbackfn 是一个回调函数,通过这个回调函数指定排序的规则

两个方法改变了原数组

var arr = [10, 20, 30, 40, 50, 60];
console.log("原数组 arr", arr);
// 原数组 arr (6) [10, 20, 30, 40, 50, 60]

// reverse()  对数组中的元素进行倒叙排列,没有参数
arr.reverse();
console.log("倒叙后 arr", arr);
// 倒叙后 arr (6) [60, 50, 40, 30, 20, 10]

// sort(callbackfn)  对数组中的元素进行排序
var array = [10, 8, 34, 90, 23, 123, 67, 89];
console.log("原数组 array", array);
// 原数组 array (8) [10, 8, 34, 90, 23, 123, 67, 89]

// 不添加任何参数,默认按照 ASCII 码 排序
array.sort();
console.log("默认排序后 array", array);
// 默认排序后 array (8) [10, 123, 23, 34, 67, 8, 89, 90]


// 通过 回调函数指定排序的规则
// 指定升序的规则(按照数值大小)
array.sort(function (a, b) {
    return a - b
})
console.log("指定升序的规则 array:", array);
//指定升序的规则 array: (8) [8, 10, 23, 34, 67, 89, 90, 123]

// 指定降序的规则(按照数值大小)
array.sort(function (a, b) {
    return b - a;
});
console.log("指定降序的规则 array:", array);
//指定降序的规则 array: (8) [123, 90, 89, 67, 34, 23, 10, 8]

(4) 数组的遍历

使用 for 循环,一一获取数组中的元素

var arr = ["苹果", "香蕉", "橘子", "火龙果", "橙子"];

// 使用 for 循环是对数组进行遍历,也就是一一获取数组中的元素  数组索引从 0 开始
for (var i = 0; i < arr.length; i++) {
    console.log("数组中第" + (i + 1) + "个元素是:" + arr[i]);
}

// 数组中第1个元素是:苹果
// 数组中第2个元素是:香蕉
// 数组中第3个元素是:橘子
// 数组中第4个元素是:火龙果
// 数组中第5个元素是:橙子

二十六、字符串对象

字符串是由引号包裹的文本

字符串除了可能是基本数据类型外,还可能使用引用数据类型,所以它比较特殊。

字符串是一个类数组,既是类数组,就具有索引和长度,索引从 0 开始,长度通过 length 属性获取

类数组可以通过索引去读取对应的值,但是不能添加和修改

举例: “Hello” ‘男’

(1) 字符串对象的创建方式

  • 字面量的方式 var str = “Hello World!”
  • new 关键字 var str = new String()
    • String() 构造函数中可以添加字符串参数 如: var str = new String(“Hello World!”)
// 字符串对象的创建方式一:字面量方式
var str = "Hello String";
console.log("str:", str, "数据类型:", typeof str);
// str: Hello String 数据类型: string  这是一个基本的数据类型


// 通过索引去读取对应的字符
console.log("字符串的第一个字符", str[0]);// 字符串的第一个字符 H
console.log("字符串中字符的个数", str.length);// 字符串中字符的个数 12
console.log("字符串中最后一个字符", str[str.length - 1]);// 字符串中最后一个字符 g


// 通过索引不可以修改和添加字符
str[5] = "&";
console.log("str", str);// str Hello String

// 字符串的创建方式二: new  关键字
var str2 = new String();
console.log("str2", str2, "数据类型:", typeof str2);
// str2 String {''} 数据类型: obj

str2 = new String("Hello new String");
console.log("str2", str2);
// str2 String {'Hello new String'}

(2) 字符串对象的属性

length 获取字符串中字符的个数

constructor 获取字符串对象的构造函数

var str = "Hello  World!";
// length  获取字符串中字符的个数
console.log("str 长度",str.length);
// str 长度 13

// constructor  获取字符串对象的构造函数
console.log("str 的构造函数",str.constructor);
// str 的构造函数 ƒ String() { [native code] }

(3) 字符串对象方法

  • concat(args…) 方法拼接一个或多个字符或字符串
    • 参数 args 字符或字符串
// 字符串拼接方法一:利用 + 运算符  只要是有字符串存在的 + 运算都是字符串拼接操作
var str = "Hello";
console.log("str", str);
// str Hello


str += " World!";
console.log("+拼接字符串 str", str);
// +拼接字符串 str Hello World!

// 字符串拼接方式二: 利用 concat()  方法
var newStr = str.concat("!", " Welcome  to code World!")
console.log("concat 拼接后原字符串 str", str);
// concat 拼接后原字符串 str Hello World!

console.log("concat 拼接后返回的新字符串 newStr", newStr);
// concat 拼接后返回的新字符串 newStr Hello World!! Welcome  to code World!
  • split(splitter,limit) 方法用来按照指定的切割符切割字符串
    • 参数 splitter 指定切割符,可以省略
    • limit 切割后,数组保留的长度

返回值是切割后的字符串组成的数组

// split(splitor) 方法用来按照指定的切割符切割字符串
var str = "Hello World! Welcome to code World!";
console.log("str", str);

// 不给任何参数:将整个字符串作为数组的元素
var arr = str.split();
console.log("arr", arr);
// arr ['Hello World! Welcome to code World!']

// 给一个参数,切割符
arr = str.split(" ");
console.log("arr", arr);
// arr (6) ['Hello', 'World!', 'Welcome', 'to', 'code', 'World!']

// 给两个参数,限定切割后数组的长度
arr = str.split(" ", 2);
console.log("arr", arr);
// arr (2) ['Hello', 'World!']

练习: 给一个字符串数据 "name=jack&age=23&sex=female,然后对其进行切割,最终形成一个类似于对象的格式’{“name”:“jack”,“age”:“23”,“sex”:“female”}’
提示: 数组的遍历、字符串的切割、字符串的拼接

var str = "name=jack&age=23&sex=female";
// 利用 split  方法进行第一次切割
var arr1 = str.split("&");
console.log("arr1", arr1);
// arr1 (3) ['name=jack', 'age=23', 'sex=female']

// 数组的遍历,获取里面的字符串元素
var str = "{";
for (var i = 0; i < arr1.length; i++) {
    // console.log(arr1[i]);

    // 使用 split 方法进行二次切割
    var arr2 = arr1[i].split("=")
    // console.log("arr2",arr2);

    str += "\"",
        str += arr2[0] + "\"",
        str += ":\"",
        // str += "\"",
        str += arr2[1] + "\"";

    if (i != arr1.length - 1) {
        str += ","
    }
}
str += "}";
console.log("str", str);
// str {"name":"jack","age":"23","sex":"female"}
  • 截取字符串的方法

    • slice(startIndex,endIndex) 获取指定索引之间的字符串片段,左闭右开
    • subString(startIndex,endIndex) 获取指定索引之间的字符串片段,左闭右开
    • subStr(startIndex,howmany) 获取指定索引处开始指定数量的字符串片段

    返回值都是截取的字符串片段

var str = "Hello World! welcome to code world!";
console.log("str:", str);
// str: Hello World! welcome to code world!


// slice(startIndex,endIndex) 获取指定索引之间的字符串片段,左闭右开
// 没有任何参数  直接相当于复制字符串
var sliceStr = str.slice();
console.log("sliceStr", sliceStr);
// sliceStr Hello World! welcome to code world!

// 指定一个参数  从这个指定索引开始截取到字符串的最后
sliceStr = str.slice(13);
console.log("sliceStr", sliceStr);
// sliceStr welcome to code world!


// 指定两个参数  获取两个参数之间的字符串片段[a,b)
sliceStr = str.slice(13, 20);
console.log('sliceStr', sliceStr);
// sliceStr welcome

// substring(startIndex,endIndex)  获取指定索引之间的字符串片段,左闭右开
// 用法  同 slice  可以不设置参数、一个参数、两个参数
subStr = str.slice(13, 20);
console.log("subStr", subStr);
// subStr welcome

// substr(startIndex,howmany) 获取指定索引处开始指定数量的字符串片段
var newStr = str.substr();
console.log("newStr", newStr);
// newStr Hello World! welcome to code world!

newStr = str.substr(13);
console.log("newStr", newStr);
// newStr welcome to code world!

// 两个参数:第一个参数是截取的起始索引  第二个参数截取的字符串个数
newStr = str.substr(13, 7);
console.log("newStr", newStr);
// newStr welcome
  • 索引相关的方法
    • charAt(index) 获取指定索引处的字符([index]也能获取)
    • indexOf(searchVale,startIndex?) 从指定索引处开始查找指定字符第一次出现的索引值,如果找到不返回-1
    • lastIndexOf(searchVale,startIndex?) 从指定索引处开始查找指定字符最后一次出现的索引值
var str = "Hello  world! welcome to code world!";

// charAt(index)  获取指定索引处的字符  ([index]  也能获取)
// 同样  charAt 方式也是只能读取数据 不能修改数据
var code = str.charAt(7);
console.log("code", code); // code w

code = str[7];
console.log("code", code);// code w


// indexOf(searchVale,startIndex?)  从指定索引处开始查找指定字符第一次出现的索引值,如果找不到返回 -1
// 只有一个参数,默认从第一个索引开始查找
var idx = str.indexOf("o");
console.log("查找的 o 在字符串中第一次出现的位置", idx);
// 查找的 o 在字符串中第一次出现的位置 4


// 两个参数:第一个参数为要查找字符串或字符片段   第二个参数指定起始查找的索引
idx = str.indexOf("o", 12);
console.log("从索引 12 开始查找的 o 在字符串中第一次出现的位置:", idx);
// 从索引 12 开始查找的 o 在字符串中第一次出现的位置: 18


// lastIndexOf(searchVale,startIndex?)  从指定索引处开始查找指定字符串最后一次出现的索引值
// 用法同  indexOf()  只不过从后往前找,但是索引还是正向从 0 开始计算
var idxs = str.lastIndexOf("o");
console.log("o 在字符串中最后一次出现的索引", idxs);
// o 在字符串中最后一次出现的索引 31
  • 转换大小写的方法
    • toUpperCase() 将字符串中所有的英文字母转为大写
    • toLowerCase() 将字符串中所有的英文字母转为小写
    • 没有参数
    • 返回值 转换后的新字符串
var str = "Hello world! welcome to code world!";
console.log("原字符串str", str);
// 原字符串str Hello world! welcome to code world!

var lowStr = str.toLocaleLowerCase();
console.log("转为小写后的 lowStr", lowStr);
// 转为小写后的 lowStr hello world! welcome to code world!

var upStr = str.toUpperCase();
console.log("转为大写后的 upStr", upStr);
// 转为大写后的 upStr HELLO WORLD! WELCOME TO CODE WORLD!

二十七、正则表达式对象

概述:
正则表达式(regular expression) 描述了一种字符串匹配模式(pattern);
可以用来检查一个串中是否包含某种子串、将匹配的子串替换或从某个串中取出符合某个条件的子串等.

(1) 正则表达式对象的创建方式

  • 字面量的方式 var patt = /匹配模式/修饰符;
    // 边界的意思 修饰符可以省略
var str = "Hello  China! 你好,中国!";

// 匹配汉字   unicode 码  是一个固定用法,中文只能在正则表达式里这样表示
var patt = /[\u4e00-\u9fa5]/;

// test()  匹配指定字符串中是否含有指定规则的字符  
// 返回一个布尔值,匹配成功  返回  true  否则返回 false

console.log(patt.test(str)); // true
console.log(patt.test("Hello")); // false
  • **使用 new 关键字 var patt = new RegExp(/匹配模式/.修饰符); **
// 匹配字符串中是否含有数字
var reg = new RegExp(/[0-9]/);
console.log(reg.test("hehe")); // false
console.log(reg.test("hehe123")); // true

(2) 正则表达式中的方法

test() 检测一个字符串是否匹配某种模式,如果字符串中含有匹配的文本,则返回 true,否则返回 false
exec() 检索字符串中的指定值;返回符合指定规则的第一个字符或字符串信息,返回值是一个数组

var patt = /[\u4e00-\u9fa5]/;

// test()  检测一个字符串是否匹配某种模式,如果字符串中含有匹配的文本,则返回 true ,否则返回 false
console.log(patt.test("test 方法检测本字符串中是否含有汉字!!")); // true
console.log(patt.test("test  method test string has chinese ?")); // false

// exec()  检索字符串中的指定值;返回符合规则的第一个字符或字符串信息,返回值是一个数组
console.log(patt.exec("exec 检测本字符串符合规则的第一个字符!!"));
// ['检', index: 5, input: 'exec 检测本字符串符合规则的第一个字符!!', groups: undefined]
console.log(patt.exec("exec method get the first chinese char in  string"));
// null 

(3) 字符串中可以使用正则表达式的方法

  • split() 按照指定的匹配模式去切割字符串,返回切割后的字符串组成的数组
  • replace() 按照指定的规则替换字符串中的字符
  • search() 查找符合指定匹配规则的字符在原字符串中第一次出现的位置
  • match() 查找符合指定规则的字符或字符串信息,并返回一个数组
var str = "你好,Jack! 欢迎来到中国!";

// split()  按照指定的匹配模式去切割字符串,返回切割后的字符串组成的数组
var arr = str.split(' ');
console.log("arr", arr);
// arr (2) ['你好,Jack!', '欢迎来到中国!']

var pattArr = str.split(/\s/);
// \s  正则表达式中的元字符  代表空格
console.log("pattArr:", pattArr);
// pattArr: (2) ['你好,Jack!', '欢迎来到中国!']


// replace()  按照指定的规格替换字符串中的字符   返回一个新的字符串
// 替换  字符串片段  Jack
var rStr = str.replace("Jack", "Lucy");
console.log("rStr", rStr);
// rStr 你好,Lucy! 欢迎来到中国!

var regStr = str.replace(/Jack/, "David");
console.log("regStr", regStr);
// regStr 你好,David! 欢迎来到中国!


// 替换 !  为 。
rStr = str.replace("!", "。")
console.log("rStr", rStr);
// rStr 你好,Jack。 欢迎来到中国!


var regStr = str.replace(/!/g, "。");
// 正则表达式中的修饰符  g 执行全局匹配    会将所有匹配到的内容进行替换
console.log("regStr", regStr);
// regStr 你好,Jack。 欢迎来到中国。


// search()  查找符合指定匹配规则的字符串中第一次出现的位置
var idx = str.search("!");
console.log("idx", idx); // idx 7 


var regIdx = str.search(/[a-z]/);
console.log("regIdx", regIdx); // regIdx 4
  • match() 和 exec() 方法的区别:
// 匹配中文的正则表达式
var patt = /[\u4e00-\u9fa5]/;


// 声明一个字符串
var str = "你好,Jack! 欢迎来到中国!";


// exec() 正则表达式中的方法。检索字符串中的指定值;返回符合指定规则的第一个字符或字符串信息,返回值是一个数组
var execArr = patt.exec(str);
console.log("execArr", execArr);
// execArr ['你', index: 0, input: '你好,Jack! 欢迎来到中国!', groups: undefined]


// match()  字符串方法。查找符合指定规则的字符或字符串信息,并返回一个数组
var matchArr = str.match(patt);
console.log("matchArr", matchArr);
// matchArr ['你', index: 0, input: '你好,Jack! 欢迎来到中国!', groups: undefined]
var str = "你好,Jack! 欢迎来到中国!";

// 执行全局匹配的正则表达式
var patt2 = /[\u4e00-\u9fa5]/g;


execArr = patt2.exec(str);
console.log("execArr:", execArr);
// execArr: ['你', index: 0, input: '你好,Jack! 欢迎来到中国!', groups: undefined]


matchArr = str.match(patt2);
console.log("matchArr", matchArr);
// matchArr (8) ['你', '好', '欢', '迎', '来', '到', '中', '国']


// 区别: 一个是正则表达式中的方法,正则表达式对象才可以调用;一个是字符串中的方法,只能是字符串对象进行调用
// 在执行全局匹配时,修饰符  g 对  exec  方法无效

(4) 修饰符

  • g 执行全局匹配
  • i 执行忽略大小写的匹配
  • m 执行多行匹配
// g  执行全局匹配
var pass = "xshls123";
var arr = pass.match(/[s-z]/);
console.log("没有执行全局匹配,返回每一个符合条件元素组成的数组:", arr);
// 没有执行全局匹配,返回每一个符合条件元素组成的数组: ['x', index: 0, input: 'xshls123', groups: undefined]

arr = pass.match(/[s-z]/g);
console.log("执行全局匹配,返回所有符合条件元素组成的数组:", arr);
// 执行全局匹配,返回所有符合条件元素组成的数组: (3) ['x', 's', 's']


// i  指定忽略大小写的匹配
var str = "Hello  world!";
var arr2 = str.match(/[A-K]/g);
console.log("没有执行忽略大小写的操作arr2", arr2);
// 没有执行忽略大小写的操作arr2 ['H']

var arr2 = str.match(/[A-K]/gi);
console.log("执行忽略大小写的操作arr2", arr2);
// 执行忽略大小写的操作arr2 (3) ['H', 'e', 'd']


// m 执行多行匹配
var mStr = "Hello\nworld!";// \n 换行的转义符
console.log("mStr: ", mStr);
// mStr:  Hello
// world!


// 匹配字符串中的单词是否有以  W 开头的单词
var patt = /^w/;
// ^ 正则表达式中的量词,代表以 指定模式开头 注意此 ^ 位置紧跟在起始边界后面
var flag = patt.test(mStr);
console.log("没有执行多好匹配的结果:", flag === true ? "存在 w 开头的单词" : "不存在 w 开头的单词");
// 没有执行多好匹配的结果: 不存在 w 开头的单词


patt = /^w/m;
flag = patt.test(mStr);
console.log("执行多行匹配的结果:", flag === true ? "存在w开头的单词" : "不存在w开头的单词");
// 执行多行匹配的结果: 存在w开头的单词

(5) 方括号

用于查找某个范围内的字符
在这里插入图片描述
注意:[A-z] 这里有 六个 特殊的字符存在于 Z 到 a 之间,所以严格意义上讲,它并不能真正的匹配所有英文字母,因为还有可能匹配到特殊字符,详见 ASCLL 码表

var str = "an123Zs1`+=ex|\hg[000]*^44ioS";
var patt = /[A-z]/g;

console.log(str.match(patt));
// (15) ['a', 'n', 'Z', 's', '`', 'e', 'x', 'h', 'g', '[', ']', '^', 'i', 'o', 'S']


// 严格上,如果只是匹配所有的大小写英文字母,请使用以下匹配方式
// patt = /[A-Za-z]/g;
patt = /[A-Z]/gi;
console.log(str.match(patt));
// (11) ['a', 'n', 'Z', 's', 'e', 'x', 'h', 'g', 'i', 'o', 'S']

// [abc]  查找方括号之间的任何字符
patt = /[a3zo85vs]/gi;
console.log(str.match(patt));
// (6) ['a', '3', 'Z', 's', 'o', 'S']

// [^abc] 查找任何不在方括号之间的字符
patt = /[^a3zo85vs]/gi;
console.log(str.match(patt));

// (22) ['n', '1', '2', '1', '`', '+', '=', 'e', 'x', '|', 'h', 'g', '[', '0', '0', '0', ']', '*', '^', '4', '4', 'i']

(6) 元字符

元字符(Metacharacter) 是拥有特殊含义的字符:
在这里插入图片描述

var str = "Hello123";
// 指定匹配规则,匹配所有的数字
// var  patt = /[0-9]/g;
var patt = /\d/g;
console.log(str.match(patt));
// (3) ['1', '2', '3']


// 指定匹配规则,匹配所有的非数字
//patt = /[^0-9]/g;
patt = /\D/g;
console.log(str.match(patt));
//(5) ['H', 'e', 'l', 'l', 'o']

(7) 量词

在这里插入图片描述
需求: 匹配网址,网址以 http 和 https 开头 后面是 😕/www. 后面是域名由 3-10 位的英文或数字 后面 .com 或 .cn 或 .net

<input type="url" id="url" placeholder="请输入合法的网址" value="">
<span id="tip"></span>

// 通过 id 去获取元素
var url = document.getElementById("url");
var tip = document.getElementById("tip");

// 网址 以 http  和 https 开头  后面是  ://www.   
// 后面是域名由 3-10 位的英文或数字  后面.com  或 .cn   或 .net 
var patt = /^http(s)?:\/\/w{3}\.[A-Za-z0-9]{3,9}\.(com|cn|net)$/;

// 设置表单正在输入的事件
url.oninput = function () {
    // console.log("对方正在输入");
    // this 指代指定事件函数的那个元素  也就是   input#url
    // console.log(this.value, "数据类型", typeof(this.value));

    // 输入的过程中验证是否符合规则
    if (patt.test(this.value)) {
        // 向页面元素中写入内容
        tip.innerHTML = "网址符合规则 √";
        // 修改文本的颜色
        tip.style.color = "green";
    } else {
        tip.innerHTML = "网址不符合规则  ×";
        tip.style.color = 'red';
    }
}

二十八、DOM 整体感知

  • DOM: DocumentObjectModel 文档对象模型 封装一些操作文档相关的 API
    DOM 描绘了一个层次化的节点树,允许开发人员添加、移除和修改页面的某一部分

这使得 JavaScript 操作 HTML, 不是在操作字符串,而是在操作节点,极大的降低了编程难度

DOM 对很多东西做了抽象,提供了丰富的 API: 取得元素、css样式、事件、运动、元素尺寸位置、节点操作。

DOM Tree 如下:
在这里插入图片描述

(1) 节点属性

  • nodeName 节点名称
  • nodeValue 节点值; 不是所有的节点都具有节点值
  • nodeType 节点类型;获取的是一个数字,对应指定的节点类型
    • **元素节点 -1 属性节点 -2 文本节点 -3 注释节点 -8 文档节点 -9 **

附录: 节点类型表
一个 HTML 或 XML 文档的文件,元素,属性等有不同的节点类型
有 12 种不同的节点类型,不同的节点类型也可以有不同的子节点类型;
在这里插入图片描述
在这里插入图片描述

(2) DOM 属性

  • document 获取文档对象
  • document.documentElement 获取根元素 html
  • document.body 获取 body 元素
  • document.title 获取 title 元素中的文本,也就是获取页面的标题文本
console.log("文档的节点名称:", document.nodeName, "节点类型", document.nodeType, "节点值", document.nodeValue);
// 文档的节点名称: #document 节点类型 9 节点值 null


var html = document.documentElement;
console.log("html 元素节点名称:", html.nodeName, "节点类型:", html.nodeType, "节点值", html.nodeValue);
// html 元素节点名称: HTML 节点类型: 1 节点值 null


var title = document.getElementsByTagName("title")[0];
console.log("title", title, "节点名称", title.nodeName, "节点类型", title.nodeType);
// title <title>​Document​</title>​ 节点名称 TITLE 节点类型 1 

// var tTxt = document.title;  // 通过这种方式获取的文本没有当作节点来处理  "string"

var tTxt = title.firstChild;// 获取第一个子节点  "object" 节点对象
console.log("tTxt  文档标题内容的节点名称", tTxt.nodeName, "节点类型:", tTxt.nodeType, "节点值:", tTxt.nodeValue);
// tTxt  文档标题内容的节点名称 #text 节点类型: 3 节点值: Document

(3) 获取元素的方法

  • **getElementById(id) ** 通过 id 去获取唯一的元素;参数为元素的 id 值,字符串类型
  • getElementByClassName(className) 通过类名去获取元素的集合
  • getElementByTabName(tagName) 通过标签名去获取元素的集合
	<h2 id="tit">通过 id 获取元素</h2>
    <section class="item">通过类名去获取元素的集合</section>
    <section class="item item2">通过类名去获取元素的集合</section>
    <section class="item item3">通过类名去获取元素的集合</section>
    <section>通过标签名去获取元素的集合</section>


        
    // getElementById(id)   通过id 去获取唯一的元素;参数为元素的 id 值,字符串类型
    var tit = document.getElementById("tit");
    console.log("tit", tit);
    // tit <h2 id=​"tit">​通过 id 获取元素​</h2>​


    // getElementByClassName(className)  通过类名去获取元素的集合
    var cSts = document.getElementsByClassName("item");
    console.log("cSts", cSts);
    // cSts HTMLCollection(3) [section.item, section.item.item2, section.item.item3]


    // getElementByTagName(tagName)  通过标签名去获取元素的集合
    var tSts = document.getElementsByTagName("section");
    console.log("tSts", tSts);
    //tSts HTMLCollection(4) [section.item, section.item.item2, section.item.item3, section] 

(4) 向页面输出数据的方式

  • document.write(); 直接向文档中写入内容
  • **element.innerHTML = “内容” ** 向标签中写入内容
    注: 内容可以是 html 标签,也可以是文本等
 <h2 id="tit">写入或读取内容的方式</h2>
    <div id="box"></div>
    <button id="btn">点击添加内容</button>

    // document.write();  直接向文档中写入内容
    document.write("<span style='color:red'>document 随页面加载写入的内容</span>")


    // 获取内容
    var btn = document.getElementById("btn");
    // btn.onclick = function () {
    //     // 这也算一个异步执行的语句,页面加载函数不会执行,只有在点击按钮时才会触发
    //     document.write("点击按钮后追加的内容");// 异步执行时,替换了结构中的所有内容所以不建议过多使用
    // }


    // element.innerHTML = "内容";  向标签中写入内容
    var box = document.getElementById("box");
    btn.onclick = function () {
        box.innerHTML = "<strong>通过点击按钮向 div 中插入的内容</strong>"
    }

    // 获取元素中的内容
    var tit = document.getElementById("tit");
    console.log("h2 中的文本为:", tit.innerHTML);
    // h2 中的文本为: 写入或读取内容的方式

(5) 添加和获取 html 属性的方式

① 对象的方式
JS 中除了 undefined 以外,都可以看作是对象;只要是具有相关的属性或方法,就可以使用对象的方式进行调用。对象的方式添加或者调用属性的语法如下

	点语法:  obj.att
	方括号语法   obj["att"]

② 内置 set / get 方法

  • setAttribute(att,val) 设置指定属性 att 的属性值为 val
  • getAttribute(att) 获取指定属性 att 的属性值

获取 html 属性:

<!-- html 标准中规定,标签自定义属性以  data-  开头 -->
<ul type="circle" id="list" data-type="square">
    <li>html 属性的设置和获取</li>
    <li>html 属性的设置和获取</li>
    <li>html 属性的设置和获取</li>
    <li>html 属性的设置和获取</li>
</ul>

var list = document.getElementById("list");

// 通过对象打点的语法去获取指定属性  type 的值
console.log("对象点语法的方法获取 type 的值:", list.type);
// 对象点语法的方法获取 type 的值: circle 

// 通过 getAttribute() 方法获取属性 type 的值
console.log("getAttribute 方法获取 type 的值:", list.getAttribute("type"));
// getAttribute 方法获取 type 的值: circle

// 总结一:  html 标签中自带的属性,两种方式都能正确的获取到

// data-  自定义属性值的获取
// console.log("对象点语法的方式获取 data-type 的值:",list.data-type);
// JS 语法中关于命名的规则:标识符必须由数字、字母、下划线、$符组成  所以上面报错  type is not defined

console.log("对象中括号的方式获取 data-type 的值:", list["data-type"]);
// 对象中括号的方式获取 data-type 的值: undefined

console.log("getAttribute 方式获取 data-type 的值:", list.getAttribute("data-type"));
// getAttribute 方式获取 data-type 的值: square


// 总结二: 如果是通过  data-  方法自定义的 html 标签属性,只能通过  getAttribute 方法获取

设置 html 属性

    <style>
        section {
            width: 300px;
            height: 300px;
            background-color: red;
        }

        .bg-blue {
            background-color: blue !important;
        }
    </style>
</head>

<body>
    <button>上一页</button>
    <img src="./images/cat.jpg" alt="" id="img">
    <button>下一页</button>

    <section id="box"></section>

    <script>

        var img = document.getElementById("img");

        img.onclick = function () {
            // 当点击图片后,切换另外一张图片: 通过修改  src 属性的路径值
            // 对象的点语法
            this.src = "./images/cat2.jpg";// this 指代执行事件的元素
        }


        // 获取  section#box
        var box = document.getElementById("box");

        box.onclick = function () {
            // 对象点的方式
            // this.class = "bg-blue";

            // 由于 class 是 js 中的关键字,这种方式不被允许:所以一旦涉及到关键字或者保留字相关的,一般 JS 会做一些处理,如在 JS 中类名使用 className
            // this.className = "bg-blue"

            // 通过 setAttribute  的方法给标签设置类名
            this.setAttribute("calss", "bg-bule")
        }


        // 总结一:  setAttribute  属性完全参照  html  中的命名  而对象的方式,在 JS 中部分相关冲突属性进行了重新命名


        // 上面操作的还是元素本身具备的属性,假设想要给 html 标签自定义 html  属性并呈现到结果标签中,那么只能使用  setAttribute 方法
        box.data = "hehe";
        box["data-msg"] = "haha";
        box.setAttribute("data-set", "xixi")


    </script>

(6) 添加和获取 CSS 行内样式

css 行内样式: 通过 html 的 style 标准属性进行添加的样式叫做行内样式

 <div style="color:red;font-size:20px;font-family:楷体">文本</div>

style 此时作为 html 属性存在,所以通过它添加样式的方式 和 添加 html 属性类似

  • 对象的方式添加和获取样式 obj.style.prop 或 obj[‘style’].prop

添加单个样式

 <div id="box"></div>
   
    <script>

        var box = document.getElementById("box");


        // 向元素内写入文本
        box.innerHTML = "获取和设置行内样式";
        //  打印所有可以添加的样式对象
        console.log(box.style);

        // 添加单个样式
        // 通过对象的方式添加样式
        box.style.color="blue";
        box['style'].border = "solid  1px red";

添加多个样式

// 向元素内写入文本
box.innerHTML = "获取和设置行内样式";
//  打印所有可以添加的样式对象
console.log(box.style);

box.style = "font-weight:bold;text-decoration:line-through;"
// 下面的样式会覆盖上面的样式
box.style.cssText = "font-style:italic;font-size:20px;"
// 添加多个样式时,由于直接对 style 进行设置,所以覆盖了之前其他设置的样式

通过 get/set 方法获取和设置

getAttribute(‘style’)

setAttribute(‘style’,‘设置的样式值’)

var box = document.getElementById("box");


// 向元素内写入文本
box.innerHTML = "获取和设置行内样式";
//  打印所有可以添加的样式对象
console.log(box.style);

// 通过  setAttribute() 方法设置样式
box.setAttribute("style","width:400px;height:100px;background-color:pink;")

获取 css 的样式值

<div id="box"></div>
   
    <script>

        var box = document.getElementById("box");


        // 向元素内写入文本
        box.innerHTML = "获取和设置行内样式";
        //  打印所有可以添加的样式对象
        console.log(box.style);

        // 通过  setAttribute() 方法设置样式
        box.setAttribute("style","width:400px;height:100px;background-color:pink;")



        console.log(box.style);

        // CSSStyleDeclaration  样式对象,封装了可以被添加的所有样式

        // 对象是由大括号包裹的名值对 {name:'jack',age:23}
        console.log(box.style.backgroundColor);
        // pink  可以从样式对象中提取指定单个样式的值

        console.log(box.getAttribute("style"));
        // width:400px;height:100px;background-color:pink;

        console.log(typeof(box.getAttribute('style')));
        // string   一个字符串类型  基本数据类型所以 get 方式没有办法获取单一指定样式,它只能获取  html 属性 style 全部的值

(7) 添加和获取非行内样式

关于添加非行内样式,可以借助 html 的属性如 calss、id等,利用其在 css 中设置指定的选择器样式,通过添加类名或 id 名实现非行内样式的添加
这里是获取非行内样式的方式,涉及到浏览器兼容的问题

    <style>
        #box {
            width: 500px;
            height: 200px;
            color: blue;
            font-size: 20px;
            font-family: "楷体";
            background-color: orange;
        }
    </style>
</head>

<body>
    <div id="box">非行内样式的获取方式</div>

    <script>

        var box = document.getElementById("box");

        // IE8 以上 及 其他浏览器 通过 window.getComputedStyle() 获取非行内样式

        // var outCss = window.getComputedStyle(box);
        // console.log(outCss); 
        // Chrome 浏览器: CSSStyleDeclaration   
        // Firefox 浏览器: CSS2Properties(352)
        // IE8 以上高版本:[object CSSStyleDeclaration]


        // IE8 及以下浏览器版本:对象不支持 "getComputedStyle" 属性或方法

        // 如果是 IE8 及以下浏览器,使用 element.currentStyle 方法获取

        // var ieoCss = box.currentStyle;
        // console.log(ieoCss);
        // IE8 以上版本 [object MSCurrentStyleCSSProperties] 对象
        // IE8 及以下 [object object]  其他浏览器 undefined

        // 所以由于两种方式都不能互相兼容,而如果有必要考虑一些  IE 低版本用户的情况下,代码需要进行一个能力检测
        // 封装一个函数,用来兼容各个版本和厂商的浏览器,可以获取外部的样式对象


        function getOutCss(e) {
            var result = null;
            if (window.getComputedStyle) {
                // 判定高版本浏览器是否兼容
                result = window.getComputedStyle(e);
            } else if (e.currentStyle) {
                result = e.currentStyle
            }

            return result
        }

        console.log(getOutCss(box));

        // 获取单一的样式
        console.log(getOutCss(box).fontFamily);// 楷体

    </script>

二十九、JS 中的事件

(1) 窗口的事件

  • window.onload html 结构或图片加载完成后执行的事件
  • window.onscroll 滚动条事件
  • window.onresize 浏览器窗口发生改变的事件
    <script>
        var box = document.getElementById("box");
        console.log("1111", box); // null
    </script>

    <script>
        // window.onload   html 结构或图片加载完成后执行的事件
        window.onload = function () {
            var box = document.getElementById("box");
            console.log("2222", box);
        }
    </script>
</head>

<body style="height: 2000px;">
    <div id="box">窗口事件</div>
    <div id="box2"
        style="height:100px;width:100px;background-color:red;position:fixed;right:10px;bottom:10px;display:none;"></div>


    <script>
        var box = document.getElementById("box");
        var box2 = document.getElementById("box2");

        console.log("3333", box);

        // window.onscroll  滚顶条事件
        window.onscroll = function () {
            var mt = document.documentElement.scrollTop;
            console.log("滚动条滚动了...页面卷去", mt + "px");

            if (mt > 300) {
                box2.style.display = "block"
            }
        }

        // 获取当前浏览器窗口的宽和高
        var aw = window.innerWidth;
        var ah = window.innerHeight;
        console.log("原窗口的宽:" + aw + "px" + "高:" + ah + "px");


        // window.onresize   浏览器窗口大小发生改变的事件
        window.onresize = function(){
            aw = window.innerWidth;
            ah = window.innerHeight;
            console.log("窗口发生改变了!改变后的宽:" + aw + "px," + "高:" + ah + "px");
        }

    </script>

(2) 鼠标事件

  • onclick 单击;点击事件
  • ondbclick 双击
  • oncontextmenu 右键
  • onmouseover 鼠标悬停
  • onmouseout 鼠标离开
  • onmousedown 鼠标按下
  • onmouseup 鼠标松开
  • onmousemove 鼠标移动

<style>
      #box {
          width: 600px;
          height: 200px;
          background-color: red;
      }
  </style>
</head>

<body>

  <div id="box">

  </div>

  <script>

      var box = document.getElementById("box");

      box.onclick = function () {
          console.log("onclick  单击事件");
      }

      box.ondblclick = function () {
          console.log("ondbclick  双击事件");
      }

      box.oncontextmenu = function () {
          console.log("oncontextmenu  右击事件");
      }

      box.onmouseover = function () {
          console.log("onmouseover  鼠标悬停");
      }

      box.onmouseout = function () {
          console.log("onmouseout  鼠标离开事件");
      }

      box.onmousedown = function () {
          console.log("onmousedown  鼠标按下事件");
      }

      box.onmouseup = function () {
          console.log("onmouseup  鼠标松开事件");
      }

      box.onmousemove = function () {
          console.log("onmousemove  鼠标移动事件");
      }
  </script>

利用 onclick 做一个图片切换的小项目,实现可以循环播放效果

<button id="prev">上一张</button>
<img src="./images/0.jpg" id="carousel" alt="图片加载失败,请检查路径....">
<button id="next">下一张</button>


<script>
    // 获取相关元素
    var prev = $("prev");
    var carousel = $("carousel");
    var next = $("next");

    // 封装一个获取相关元素的函数
    function $(id) {
        return document.getElementById(id)
    }

    // 信号量: 随着信号的强弱会有一定的变化
    // 定义一个变量,来统计信号的编号
    var count = 0;

    // 设置下一张按钮的点击事件,点击一次,信号加 1 
    next.onclick = function () {
        // count++;
        // console.log("count",count);

        if (++count > 5) {
            // 如果到最后一张,还在点击下一张,那么就切换到第一张
            count = 0;
        }

        // 切换下一张图片
        carousel.src = "./images/" + count + ".jpg";
    }

    // 设置上一张按钮的点击事件,点击一次,信号减 1 
    prev.onclick = function () {
        // count--;
        // console.log("count",count);

        if (--count < 0) {
            // 如果到第一张,还在点击上一张,那么就切换到最后一张
            count = 5;
        }

        // 切换上一张图片
        carousel.src = "./images/" + count + ".jpg";
    }

</script>

在这里插入图片描述

(3) 表单事件

这个需要 form 标签来进行事件的驱动

  • onfocus 获取焦点
  • onblur 失去焦点
  • onchange 数据发生改变
  • oninput 正在输入
  • onsubmit 表单提交
  • onreset 表单重置
   <style>
        * {
            margin: 0;
            padding: 0;
        }

        .item {
            width: 250px;
        }
    </style>
</head>

<body>
    <form action="/regist" target="_blank" id="form">
        <div class="item">
            <label for="">用户名</label>
            <input type="text" name="username" id="username" value="">
        </div>

        <div class="item">
            <label for="">密码:</label>
            <input type="search" name="search" id="search" value="">
        </div>

        <div class="item">
            <textarea name="" id="des" cols="30" rows="10"></textarea>
            <p align="right">当期输入了<strong id="count">0</strong>个字</p>
        </div>

        <div class="item">
            <input type="submit" id="submit">
            <input type="reset" id="reset">
        </div>
    </form>


    <script>
        // 获取相关元素
        var form = $("form");
        var uName = $("username");
        var search = $("search");
        var des = $("des");
        var count = $("count");
        var submit = $("submit");

        // onfocus  
        uName.onfocus = function () {
            console.log("获取焦点");
            this.style.backgroundColor = "#e3e3e3"
        }

        // onblur 失去焦点
        uName.onblur = function () {
            alert("失去焦点...")
        }

        // onchange  数据发生改变
        search.onchange = function () {
            console.log("数据发生改变了");
        }


        // oninput  正在输入
        des.oninput = function () {
            console.log(this.value);
            console.log(this.value.length);
            count.innerHTML = this.value.length;
        }



        // submit 和 reset  两个按钮不能触发  对应的  onsubmit 和 onreset  事件 
        // submit.onsubmit = function () {
        //     console.log("提交成功....");
        // }

        // onsubmit 和  onreset 事件  只能通过 form 这个标签触发
        form.onsubmit = function () {
            console.log("提交成功");
        }

        function $(id) {
            return document.getElementById(id)
        }

三十、批量添加事件

实现 无法获取索引的问题 以及 三种解决方式

<ul id="list">
        <li>1批量添加事件</li>
        <li>2批量添加事件</li>
        <li>3批量添加事件</li>
        <li>4批量添加事件</li>
        <li>5批量添加事件</li>
        <li>6批量添加事件</li>
    </ul>

    <script>
        var list = document.getElementById("list");

        // var fli = list.getElementsByTagName("li")[0];
        // var sli = list.getElementsByTagName("li")[1];
        // fli.onclick = function () {
        //     console.log(this.innerHTML);
        // }
        // sli.onclick = function () {
        //     console.log(this.innerHTML);
        // }
        // 上面获取单个的 li 标签,分别设置事件,很麻烦,那么有没有一个比较好的方法  简化代码 达到同样的效果


        // 利用循环,遍历所有的 li
        // 获取所有的 li 标签
        var lis = list.getElementsByTagName("li");
        // console.log(lis);
        // HTMLCollection(6) [li, li, li, li, li, li]

        // for (var i = 0; i < lis.length; i++) {
        //     lis[i].onclick = function () {
        //         console.log("点击的  li 对应的索引:" + i);
        //         // 点击的 li 对应的索引: 6  
        //         // 不管点击的哪一个,结果都是6  不能正确获取索引   而 6 又是循环完成后得到的值
        //     }
        // }
        // console.log("i:", i);// i: 6

        // 解决无法正确获取索引的问题
        // 第一种  IIFE + 闭包
        // for (var i = 0; i < lis.length; i++) {
        //     (function (j) {
        //         lis[j].onclick = function () {
        //             console.log("点击的 li 对应的索引:" + j);
        //         }
        //     })(i)
        // }
        // console.log("i:", i);


        // 第二种 利用 this  在事件函数中,this 指代执行事件的元素本身
        // for (var i = 0; i < lis.length; i++) {
        //     // 随着循环的执行,给对应的每一个 li 元素对象,设置一个自定义属性  来保存每次遍历的索引(循环的索引 又 正好对应每一个 li 的标签对应的索引)
        //     lis[i].index = i;
        //     lis[i].onclick = function () {
        //         console.log("点击 li 对应的索引:" + this.index);
        //     }
        // }
        // console.log("i:", i);


        // 第三种
        // ES6 循环中使用let初始化变量 形成一个局部作用快  可以实现同步效果
        for (let i = 0; i < lis.length; i++) {
            lis[i].onclick = function () {
                console.log("点击 li 对应的索引" + i);
            }
        }
        // console.log("i:", i);// 报错  在外面访问不到

三十一、获取随机的背景颜色

*两种方法 一个 rgb 一个十六进制

<button id="btn">点击切换背景色</button>

    <script>
        var btn = document.getElementById("btn");


        btn.onclick = function () {
            // console.log("点击了以下按钮");

            document.body.style.backgroundColor = getRanColor()
        }

        //  颜色的表示方式: 英文字母、十六进制、rgb()
        //  获取随机颜色的方法  rgb 0 - 255
        // function getRanColor() {
        //     var r = parseInt(Math.random() * 256);
        //     var g = parseInt(Math.random() * 256);
        //     var b = parseInt(Math.random() * 256);

        //     return "rgb(" + r + "," + g + "," + b + ")";
        // }

        // 十六进制   #后面跟6位  0-9,a-f 之间的随机数
        function getRanColor() {
            var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f"];

            // 声明一个变量来接收得到的每一个十六进制数
            var str = "#";

            // 循环六次
            for (var i = 0; i < 6; i++) {
                // 每一次都获取 arr 中一个随机的值
                // 想要获取随机的值,首先要获取随机索引
                var ranIdx = parseInt(Math.random() * arr.length);
                // console.log(ranIdx);
                // 拼接六位
                str += arr[ranIdx]
            }

            return str
        }

    </script>

三十二、对应思想

制作限行尾号

 <span>请选择星期几,查询限号</span>
    <div>
        <button>星期一</button>
        <button>星期二</button>
        <button>星期三</button>
        <button>星期四</button>
        <button>星期五</button>
    </div>

    <div>今日限行尾号:<strong id="show">待查询</strong></div>


    <script>
        // 数组中套数组  叫做二维数组
        var arr = [[1, 6], [2, 7], [3, 8], [4, 9], [5, 0]];

        // 外层数组有五个元素  对应于  用户选择的五个按钮
        var btns = document.getElementsByTagName("button");
        var show = document.getElementById("show");

        for (var i = 0; i < btns.length; i++) {
            // 遍历的 btns 类数组的索引  和  arr 数组的索引对应
            (function (j) {
                btns[j].onclick = function () {
                    // console.log(j);
                    // console.log(arr[j]);
                    show.innerHTML = arr[j][0] + " 和 " + arr[j][1]
                }
            })(i)
        }
    </script>

三十三、排他思想

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .container {
            width: 400px;
            margin: 100px auto;
        }

        .nav {
            list-style: none;
            display: flex;
            justify-content: space-between;
        }

        .nav li {
            width: 60px;
            padding: 4px 12px;
            text-align: center;
            border: 1px solid white;
            background-color: orange;
            cursor: pointer;
        }

        .nav li.on {
            color: white;
            font-weight: bold;
            background-color: red;
        }

        .content {
            padding: 10px;
            border: solid 1px;
        }

        .content div {
            width: 200px;
            height: 200px;
            margin: auto;
            color: white;
            font-size: 60px;
            font-weight: bold;
            text-align: center;
            line-height: 200px;
            border-radius: 50%;
            background-color: purple;

            display: none;
        }

        .content div.show {
            display: block;
        }
    </style>
</head>

<body>

    <div class="container">
        <ul class="nav">
            <li class="on">第一项</li>
            <li>第二项</li>
            <li>第三项</li>
            <li>第四项</li>
            <li>第五项</li>
        </ul>


        <div class="content">
            <div class="show">1</div>
            <div>2</div>
            <div>3</div>
            <div>4</div>
            <div>5</div>
        </div>
    </div>


    <script>
        var lis = document.getElementsByTagName("li");
        var content = document.getElementsByClassName("content")[0];
        var items = content.getElementsByTagName("div");

        for (var i = 0; i < lis.length; i++) {
            lis[i].index = i;
            lis[i].onclick = function () {
                // 先清除其他的样式
                for (var j = 0; j < lis.length; j++) {
                    lis[j].classList.remove("on");
                    // 清除原来的内容
                    items[j].classList.remove("show")
                }


                // 点击这个导航 发生改变
                this.classList.add("on");
                // 显示对应的内容
                items[this.index].classList.add("show");
            }
        }



    </script>

</body>

</html>

在这里插入图片描述

三十四、计时器

(1) 间歇调用:每隔一段时间去执行一遍回调函数

window.setInterval(callbackfn,time);
callbackfn 回调函数
time 指定间隔时间;单位 ms

(2) 延迟调用:指定时间后执行一次回调函数

window.setTimeout(callbackfn,time)
callbackfn 回调函数
time 指定间隔时间,单位 ms

(3) 取消计时器的方法

clearInterval(timer) 取消间歇调用
clearTimerout(timer) 取消延迟调用
timer 指定取消的计时器名称

<button id="stop">结束打印</button>

<div><strong id="count">10</strong>秒后关闭页面.....</div>

<script>
    var stop = document.getElementById("stop");
    var count = document.getElementById("count");

    // 间歇调用
    var num = 10;
    var timer = setInterval(function () {
        count.innerHTML = --num
    }, 1000)

    stop.onclick = function () {
        // 停止计时器
        clearInterval(timer)
    }

    // 延迟调用
    // 10 秒后,关闭当前页面
    setTimeout(function () {
        // 关闭页面
        window.close();
    }, 10000)
</script>

练习: QQ 安全 或 银行密码,现在几乎都是一个动态的验证码,验证码是随机的六位数字

 <style>
        * {
            margin: 0;
            padding: 0;
        }

        .wrap {
            display: flex;
            align-items: center;
        }

        .grid {
            display: table;
            list-style: none;
        }

        .grid li {
            display: table-cell;
            padding: 4px 8px;
            border: 1px solid #000;
        }
    </style>
</head>

<body>

    <div class="wrap">
        <strong>当前动态密钥:</strong>

        <ul class="grid">
            <li>0</li>
            <li>0</li>
            <li>0</li>
            <li>0</li>
            <li>0</li>
            <li>0</li>
        </ul>
    </div>

    <script>
        // 获取所有的  li
        // 这是一个 CollectionElement  类数组
        var lis = document.getElementsByTagName("li");

        // 遍历所有的 li标签
        // for (var i = 0; i < lis.length; i++) {
        //     // 每循环一次,随机获取一个 0-9 之间的数字
        //     var ranNum = parseInt(Math.random() * 10);
        //     // 将获取的随机数,写入到遍历的这个 li 中
        //     lis[i].innerHTML = ranNum;
        // }
        // 上面只能手动刷新密码


        // 利用定时器,每隔十秒刷新动态密钥
        setInterval(refresh, 10000);
        // 定义刷新函数
        function refresh() {
            for (var i = 0; i < lis.length; i++) {
                // 每循环一次,随机获取一个 0-9 之间的任意数
                var ranNum = parseInt(Math.random() * 10);
                // 将获取的随机数,写入到遍历的这个 li  中
                lis[i].innerHTML = ranNum;
            }
        }

    </script>

三十五、对象 和 JSON

对象是特征与行为的集合,由名值对组成,大括号包裹。如: {name:“jack”,age:23}

语法格式 {键名:键值}

多个名值对使用逗号 “,” 隔开

对象属性的调用 obj.att 或 obj[“att”]

对象的方法的调用 obj.fn()

在 JS 中,除了 undefined 外,其他的任何东西都可以看作是对象

JSON 数据:
JSON(javaScript Object Notation,JS 对象简谱) 是一种轻量级的数据交换格式。它基于ECMAScript(欧洲计算机协会制定的 js 规范) 的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和生成,并有效的提升网络传输效率。

JSON 和 对象之间的关系
很多人搞不清楚 JSON 和 JS 对象的关系,甚至连谁是谁都不清楚。其实,可以这么理解:
JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
如:

// 这是一个对象,注意键名也是可以使用引号包裹的
var obj = {a:"Hello",b:"World"};
// 这是一个 JSON 字符串,本质是一个字符串
var json = '{"a":"Hello","b":"world"}'

JSON 和 JS 对象互转

要实现从 JSON 字符串转换为 JS 对象,使用 JSON.parse() 方法

var obj = JSON.parse('{"a":"Hello","b":"World"}');
console.log("obj   ",obj);
//obj    {a: 'Hello', b: 'World'}

要实现从 JS 对象转换为 JSON 字符串,使用 JSON.stringify() 方法

var json = JSON.stringify({ a: 'Hello', b: 'world' });
console.log("json", json);
// json {"a":"Hello","b":"world"}

常用类型:
任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型.

对象: 对象在 JS 中是使用花括号包裹 {} 起来的内容,数据结构为 {key1:value,key2:value2,…} 的键值对结构。在面向对象的语言中,key 为对象的属性,value 为对应的值。键名可以使用整数和字符串来表示。值得类型可以是任意类型。
数组: 数组在 JS 中是方括号 [] 包裹起来得内容,数据结构为 [“java”,“javascript”,“vb”,…] 的索引结构。在 JS 中,数组是一种比较特殊的数据类型,它也可以像对象那样使用键值对,但还是索引使用得多。同样,值的类型可以是任意类型。

// 创建一个对象
var obj = {
    name: "jsck",
    sex: "男",
    age: 23,
    sleep: function () {
        return "打呼喽"
    }
}

console.log("obj", obj, "数据类型:", typeof (obj));
// obj {name: 'jsck', sex: '男', age: 23, sleep: ƒ} 数据类型: object



// 将对象转为 JSON 串   JSON.stringify()
var str = JSON.stringify(obj);
console.log("str", str, "数据类型: ", typeof (str));
// str {"name":"jsck","sex":"男","age":23} 数据类型:  string


// 创建一个 JSON 数据
var json = '{"code":0,"city":[{"id":"010","name":"北京"},{"id":"020","name":"上海"},{"id":"030","name":"重庆"},{"id":"022","name":"天津"}]}';
console.log("json", json, "数据类型", typeof json);
// json {"code":0,"city":[{"id":"010","name":"北京"},{"id":"020","name":"上海"},{"id":"030","name":"重庆"},{"id":"022","name":"天津"}]} 数据类型 string

// 将 JSON 数据转为对象 JSON.parse()
var o = JSON.parse(json);
console.log("o:", o, "数据类型", typeof o);
// o: {code: 0, city: Array(4)}city: Array(4)0: {id: '010', name: '北京'}1: {id: '020', name: '上海'}2: {id: '030', name: '重庆'}3: {id: '022', name: '天津'}length: 4[[Prototype]]: Array(0)code: 0[[Prototype]]: Object 数据类型 object

获取上面 o 这个复杂结构中的内容:
对象获取数据 对象.属性 或 对象[属性]
数组获取数据 数组对象[索引]
在这里插入图片描述

删除对象中的属性
delete obj.att

在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大闸蟹~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值