1.while循环
1.循环结构语句 - while
+ 循环: 重复的执行某一段代码
循环三要素
+ 开始: 初始变量, 初始数字
+ 结束: 判断条件, 结束数字
+ 步长: 每次间隔多少进行数数
while 语法
+ while (条件) { 重复执行的代码 }
+ 意义:
=> 首先进行条件判断
=> 如果条件为 false, 直接结束整个循环
=> 如果条件为 true, 那么执行一遍 {} 内的代码
=> 然后再次进行条件判断
=> 如果条件为 false, 直接结束整个循环
=> 如果条件为 true, 那么执行一遍 {} 内的代码
=> 然后再次进行条件判断
=> ...
Note:使用while深度遍历,一般属性名需要相同!!!
1.1 while循环小案例
Note:下述案例都用了临时变量temp,用临时变量时定义时最好加 _ 下划线!!!!!
1.斐波那契数列
var a=1,b=1,s=a+b,str=a+"+"+b;
var _temp;
while(a+b<100){
_temp=a;
a=b;
b+=_temp;
s+=b;
str+="+"+b;
}
str+="="+s;
console.log(str) //1+1+2+3+5+8+13+21+34+55+89=232
2.卢卡斯数列
var a=1,b=3,s=a+b,str=a+"+"+b;
var _temp;
while(a+b<100){
_temp=a;
a=b;
b+=_temp;
s+=b;
str+="+"+b;
}
str+="="+s;
console.log(str) //1+3+4+7+11+18+29+47+76=196

1.2 while循环小案例
1.99乘法口诀表
var table=document.getElementById("table")
var str=""
var i=1
while(i<10){
str+="<tr>"
var j=1
while(j<=i){
str+=`<td>${i}*${j}=${i*j}</td>`
j++
}
str+="</tr>"
i++
}
table.innerHTML=str
2.100以内所有质数,素数
var i=2
while(i<100){
var j=2
var bool=true
while(j<i){
if(i%j===0){
bool=false
}
j++
}
if(bool){
console.log(i)
}
i++
}
3.最大公约数
var a=12
var b=45
var max=a>b?a:b
var min=a>b?b:a
var str
for(var i=min
if(a%i===0 && b%i===0){
str=i
break
}
}
console.log(str) //3
4.最小公倍数
var a=12
var b=45
var max=a>b?a:b
var min=a<b?a:b
var str
for(var i=max
if(i%min===0){
str=i
break
}
}
console.log(str) //180
2.break和continue和标记语法 作用
流程控制语句
1. break
2. continue
3. 标记语法
break
+ 是一个使用在循环内的关键字
+ 当循环内执行到 break 关键字的时候, 会直接结束整个循环
continue
+ 是一个使用在循环内的关键字
+ 当循环内执行到 continue 关键字的时候, 会结束循环的本次, 去到下一次(只是结束这次的循环)
标记语法(label)
+ 给循环起一个名字
+ 书写在循环的上面一行, 写 名字:
+ 当你使用 break 和 continue 关键字的时候
=> 可以书写 break 名字
=> 或者书写 continue 名字
=> 表示打断哪一个循环或者结束哪一个循环的本次
+ 用在循环嵌套内
2.1补充
1.Note:对于while使用continue,i++必须考虑在continue之前,否则会死循环!!!!!
例:var i=0
while(i<10){
i++
if(i===5) continue
console.log(i)
}
2.Note:当循环增加label(标签,标记) ,可以使用break跳出这个laebl循环
例:var i=0
xietian:while(i<10){
var j=0
while(j<10){
if(j===5) break xietian
j++
console.log(i,j)
}
i++
}
3.Note:continue跳出label时,会不执行当前循环和外层循环后面的语句!!!!!
例: var i=0
xietian:while(i<10){
i++
var j=0
while(j<10){
if(j===5) continue xietian
j++
console.log(i,j)
}
console.log("aaa")
}
3.do...while循环
循环结构语句 - do ... while
+ 和 while 循环差不多的语句
语法:
do {
重复执行的代码
} while (条件)
意义:
+ 不管条件是否满足, 首先先执行一遍 {} 内的代码
+ 开始进行条件判断
+ 如果为 false, 直接结束循环
+ 如果为 true, 那么执行一遍 {} 内的代码
+ 再次进行条件判断
+ 如果为 false, 直接结束循环
+ 如果为 true, 那么执行一遍 {} 内的代码
+ 再次进行条件判断
+ ...
区别:
+ 当初始变量在条件以内的时候, 两个循环没有区别
+ 当初始变量在条件以外的时候
=> while 循环一次都不会执行
=> do ... while 循环会执行一次
4.for循环
循环结构语句 - for
+ 循环结构语句 的一种
语法:
for (初始变量; 条件判断; 修改初始值) { 重复执行的代码 }
4.1补充
上述提到:对于while使用continue,i++必须考虑在continue之前,否则会死循环
如果使用continue时,for语句可以更完美处理这个i++的问题,不会造成死循环
例:for(var i=0;i<100;i++){
if(i===10) continue;
console.log(i)
}
5.对象
对象数据类型
+ 是 JS 内的一个复杂数据类型 - Object
+ 对象:
=> 含义1: 一类事物的某一个具体个例
=> 含义2: JS 内的一种数据类型
+ 对象数据类型
=> 私人: 是一个 "盒子", 是一个承载数据的 "盒子"
=> 是一个无序的数据集合
=> 对象是一个 键值对 的集合
创建对象数据类型
+ 字面量形式
=> 创建一个空对象: var obj = {}
=> 创建带有数据的对象: var obj = { 键值对, 键值对, ... }
-> 键值对 键: 值
+ 内置构造函数形式
=> 创建一个空对象: var obj = new Object()
1.对象的键,必须是字符串或者Symbol类型,其他任何类型都会隐式转换为字符串 !!!!!!!!
2.所有引用类型尽量使用JSON.stringify转换为字符串查看!!!!!!!!!
5.1对象数据类型的基本操作
对象数据类型的基本操作(CRUD 增删改查)
+ JS 的语法内, 对于对象的操作给出了两套语法
=> 点语法
=> 数组关联语法
1.点语法 var obj = {}
+ 增: 向对象内插入一条数据
=> 语法: 对象名.键名 = 值
+ 删: 删除对象内的某一个数据
=> 语法: delete 对象名.键名
+ 改: 修改对象内的某一个数据
=> 语法: 对象名.键名 = 值
=> 对象内的 key 不允许重复, 原先有就是修改, 原先没有就是增加
+ 查: 获取对象内某一个 key 所保存的值
=> 语法: 对象名.键名
=> 如果对象内有该键名, 那么就是该键名对应的值
=> 如果对象内没有该键名, 那么就是 undefined
2.数组关联语法
增:
=> 语法: 对象名['键名'] = 值
删:
=> 语法: delete 对象名['键名']
改:
=> 语法: 对象名['键名'] = 值
=> 原先有就是修改, 原先没有就是增加
查:
=> 语法: 对象名['键名']
3.定义对象的方法
obj.fn=function(){
}
5.1的补充
1.对象内的 key 可以是什么 ? 什么都行
1. 推荐使用 满足变量命名规则和规范 的名字
2. 可以使用纯数字, 如果你使用的是纯数字, 会排列在对象的最前面
3. 如果使用其他内容, 需要单独使用引号包裹 key
2.两种操作语法的区别
1. 如果你操作的是 满足变量命名规则和规范 的 key
=> 两个语法一模一样
2. 如果你操作的是 纯数字 或者 其他符号 的 key
=> 只能使用数组关联语法, 点语法会报错
3. 涉及变量相关的时候
=> 只能使用数组关联语法
例:var obj = {
name: 'Jack',
a$2: 100,
user_email: '11111@qq.com',
100: 200,
1: 'abc',
'c-z': 135,
'a#c': 'hello world'
}
console.log(obj)
操作语法的区别举例:!!!!!!!!!!!!!!!!!!!!!!!!!很重要的 一定要注意
1.在 JS 内, 点后面如果是数字, 那么要求前面也必须是数字(.后面为数字他就会把整个当成数值类型)
console.log(obj.100)
console.log(obj[100])
2.- 在 JS 内单独使用的时候, 就只能表示 减号
这个的意义是 obj.c 减去 z 变量
console.log(obj.c-z)
console.log(obj['c-z'])
3.涉及变量相关的时候
var a = 'name'
3.1当你使用点语法的时候, a 只能是表示一个对象内的准确的键名, 和 a 变量不可能产生任何关系
console.log(obj.a)
3.2当你使用数组关联语法, 并且中括号内直接书写的字符串的时候, 只能是准确的表示对象内的某一个键名和 a 变量没有任何关系
console.log(obj['a'])
3.3当你使用数组关联语法, 并且中括号内书写的是一个变量的时候会把该变量的值解析出来, 放在中括号内
obj[a] 等价于 obj['name']
console.log(obj[a])
5.2遍历对象
回忆: 遍历 arguments
=> 为什么使用 for 循环遍历 arguments
=> 因为 arguments 内数据的排列是按照索引排列(索引是一组有规律的数字)
=> 又因为循环可以提供一组有规律的数字
=> 我们使用循环控制变量充当索引去遍历
现在: 遍历 对象
=> 问题: 对象内的 key 没有规律
=> 使用 for in 循环的来遍历对象
=> 语法:
for (var 变量 in 对象名) {
重复执行的代码
}
例:var obj = {
name: 'Jack',
age: 18,
gender: '男',
scroe: 100
}
console.log(obj)
for (var k in obj) {
console.log('我执行了', ' ---- ', k, ' ---- ', obj[k])
}
5.2遍历对象的补充
Note:遍历顺序 !!!!!!!!!!
1.先遍历 数字属性,从小到大
2.其次按照属性的添加顺序遍历
3.不遍历Symbol属性 (目前不知)
例: var obj={}
obj.b=2
obj.a=3
obj["10"]=10
obj["1"]=1
for(var prop in obj){
console.log(prop,obj[prop])
} // 10 10
// b 2
// a 3
obj["a"]=1
console.log(obj["a"])
记住就行:对象的遍历并不是顺序
// 对象是松散结构,互相之间没有关系,所以对象不能做排序,key是唯一
// 在对象中直接通过key获取值,这种查找速度是最快的

6.深浅拷贝
1. 赋值 把 对象的地址 复制一份给到另一个变量
2. 浅拷贝(只能拷贝一层 第二层就不算拷贝了 因为:第一层的可以单独修改 第二层会共同修改也就是公用一个存储空间)
例:
var o2 = {}
for (var k in o1) {
o2[k] = o1[k]
}
console.log(o1, o2)
o1.age = 20
console.log(o1, o2)
o1.info.height = 200
console.log(o1, o2)
3. 深拷贝(你是你 我是我 我改了 你不改)
例:
function diffCopy(target, origin) {
for (var k in origin) {
if (Object.prototype.toString.call(origin[k]) === '[object Object]') {
target[k] = {}
diffCopy(target[k], origin[k])
} else {
target[k] = origin[k]
}
}
}
var o2 = {}
diffCopy(o2, o1)
console.log('拷贝结束')
console.log(o1, o2)
o1.name = 'Rose'
console.log(o1, o2)
o1.info.height = 220
console.log(o1, o2)
o1.info.address.city = '上海'
console.log(o1, o2)
o1.info.address.hobby.ball = '足球'
console.log(o1, o2)
7.判断数据类型
小问题: 判断一个数据是 对象数据类型
8.函数
认识函数数据类型 - Function
+ 复杂数据类型
+ 私人:
=> 是一个 "盒子", 一个承载一段代码的 "盒子"
函数必然经历两个阶段
1. 函数定义阶段: 把代码装进 "盒子" 的过程
2. 函数调用阶段: 把 "盒子" 内的代码执行的过程
函数定义阶段
1. 声明式函数(命名式函数)
=> 语法: function 函数名() { 代码段 }
-> function 定义函数的关键字
-> 函数名 就是一个变量名
-> () 必须写, 放置参数(欠着, 已还)
-> {} 承载代码段, 你要装进 "盒子" 的代码
2. 赋值式函数(函数表达式/匿名函数)
=> 语法: var 变量名 = function () { 代码段 }
(其中形参和实参关系不大 有实参按照实参来 没有实参默认用形参)
函数调用阶段
+ 目的: 把 函数 体内的代码执行一遍
+ 语法: 函数名()
=> 函数名 表示你要调用的是哪一个函数
=> () 调用(把函数体内的代码执行), 参数(欠着, 已还)
函数调用上的区别
+ 声明式函数可以先调用, 也可以后调用
+ 赋值式函数只能后调用, 先调用会报错 xxx is not a function
例:
1. 函数定义阶段
1-1. 声明式函数
function fn() {
console.log('我是声明式函数 fn')
}
1-2. 赋值式函数
var fun = function () {
console.log('我是赋值式函数 fun')
}
2. 函数调用阶段
2-1. 我想执行 fn 函数体内的代码
fn()
2-2. 我想执行 fun 函数体内的代码
fun()
8.1函数补充
1.如果把命名函数写在语句块中就不会预赋值
例:console.log(a);
var a=1;
{
function a(){
}
}
console.log(a);
if(a==2){
function a(){
}
}
console.log(a);
if(!a){
function a(){
}
}
console.log(a);
自执行函数(匿名函数) 认识即可
(function(){
})();
~function(){
}();
+function(){
}();
-function(){
}();
9.预解析
预解析
+ 在所有代码执行以前, 对代码进行通读并解释
解析的内容
1. var 定义的变量
=> 告诉浏览器, 我要定义一个 xxx 变量, 但是暂时不赋值
2. 声明式函数
=> 注意: 函数表达式不进行预解析
=> 告诉浏览器, 我定义了一个叫做 xxx 变量(函数名), 并且赋值为一个函数
预解析的重名问题
+ 当你定义函数名和变量名的时候, 如果重名, 以函数为准, 只是在预解析阶段
+ 不要把变量和函数名重名(属于出错的一个问题 体现了变量语义化的方便 习惯问题)
9.1命名函数的预解析和预赋值
1.块语句中同名函数变量,将会把最后一个同名函数上面赋值的变量赋值在外面的变量 !!!!!
例:var a=1
if(a===1){
a=2
function a(){ //最后一个同名函数上面赋值的变量 赋值在外面的变量
//最后一个 a=2 赋值到外面
}
a=3
}
console.log(a)
10.作用域
作用域
+ 指一个变量的使用范围
作用域的分类
1. 全局作用域
=> 一个 html 文件打开, 就是一个全局作用域
=> 叫做 window
2. 私有作用域(函数作用域)
=> **只有函数决定私有作用域**
作用域的父子关系
+ 写在哪一个作用域内的函数, 就是哪一个作用域的子级作用域
例:
function f1() {
function f2() {
}
}
function f3() {
}
10.1作用域的三个规则
作用域的三个规则 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 在作用域内一共提供了三个规则
+ 三个规则在所有作用域内通用
+ 熟读并背诵全文
变量定义规则
+ 定义在哪一个作用域下的变量
+ 就是哪一个作用域的私有变量
+ 只能在该作用域及其后代作用域内使用
+ 不能再父级作用域内使用
变量访问规则
+ 当你需要访问一个变量的值的时候
+ 首先在自己作用域内查找, 如果有, 直接使用, 停止查找
+ 如果没有, 去到父级作用域查找, 如果有直接使用, 停止查找
+ 如果还没有, 在去到父级作用域
+ 直到 全局作用域(window) 都没有
+ **那么直接报错 xxx is not defined**
变量赋值规则
+ 当你需要给一个变量进行赋值操作的时候
+ 首先在自己作用域内查找, 如果有, 直接赋值, 停止查找
+ 如果没有, 去到父级作用域查找, 如果有直接赋值, 停止查找
+ 如果还没有, 就再去父级作用域查找
+ 以此类推, 直到全局作用域(window) 都没有
+ **那么把这个变量定义为全局变量, 再进行赋值**
10.2变量赋值补充
1.函数内使用var定义的变量都是局部变量,一般会在当前函数执行完成后销毁
2.函数外是无法调用到函数内的局部变量
3.每个函数是一个独立的作用域,我们可以向上调用到父级作用域的变量,但是如果当前函数的变量与父级作用域同名时,就不能调用到父级作用域的变量
4.父级作用域是无法调用到子级作用域的变量的
例:var a=1
var b=2
var c=10
function fn(){
console.log(a)//1
console.log(b)
var c=4
function fn1(){
console.log(a)
console.log(b)
var b=3
console.log(b)
console.log(c)
}
fn1()
console.log(b)
}
fn()
console.log(c)
5.参数也是局部变量,参数属于当前函数内的局部变量 var
例:var a=1
function fn(a){
console.log(a)
// var a=2
}
fn(3)
console.log(a) //1
var a=3
function fn(b){
var a=b
}
fn(4)
console.log(a)
var a=3
function fn(a){
// 参数也是局部变量,参数相当于var a
a=7
}
fn(5)
console.log(a)
//综合体:
a(4)
{
a=4
function a(){
console.log("b")
}
a=5
function a(){
console.log("c")
}
a=6
}
// var a=3
function a(a){ //(a)里面的a是参数 参数就是局部变量 所以下面打印 7
a=7
console.log(a)//7
}
console.log(a)//5 //对应上述块语句 所以此处加上上述a=6;结果还是 5