01-JavaScript 进阶 课程介绍
1.课程目标
长远目标
- 形成高级编程人员的软件开发思维
- 掌握js语言的高级写法
- 了解一些不常用的语法
短期目标
- 更加容易吸收课程阶段的项目知识
- 为3个月后的面试和笔试打好铺垫
同学们的吸收状态
- 黄金 领略思想 看不懂代码 写不出代码
- 铂金 领略思想 看懂代码 写不出代码
- 钻石 领略思想 看懂代码 写出代码
- 星耀 灵活运用
- 王者 ?
2.课程知识
其他分支 三元运算 其他循环 对象 封装 继承 原型 原型链 函数 匿名函数 箭头函数 闭包 递归 call和apply es6-class 设计模式 冒泡算法
2.JavaScript 高级进阶 第一天
1.今日目标
- 了解Swtich-case分支
- 了解三元表达式简化分支
- 了解while循环
- 理解冒泡排序
- 理解面向对象的概念 思想
- 理解创建简单类型和复杂类型的堆栈关系(重点)
- 理解创建对象的几种方式
- 理解创建对象的优缺点 - 重点!!!
2.分支结构(3种语法)
switch-case分支结构
- 1.语法
switch(表达式){ // 不是布尔类型:是一个确定的变量
case 值1: // 值1,值2...都是字面量
表达式的结果 === 值1,需要执行的代码
break;
case 值2:
表达式的结果 === 值2,需要执行的代码
break;
case 值3:
表达式的结果 === 值3,需要执行的代码
break;
.......
default:
表达式的结果和上面所有的case后面的值都不全等,则会执行这里的代码
break;
}
2.注意事项
- 1.表达式的结果要和值一定是全等的关系===
2.break作用:结束该switch语句,所以一般情况下要加上,如果不加上则会发生穿透
- 穿透:从上一个case代码快执行到下一个case代码快
- break关键字的作用就是防止穿透
- 3.default语句可以写在任何地方,也可以省略,但是一般写在最后,这是一种代码规范
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
/**
switch-case分支结构:常用于值匹配
* 匹配:全等的关系
* switch(条件值){
case 值1:
条件值 === 值1,需要执行的代码
break;
case 值2:
条件值 === 值2,需要执行的代码
break;
case 值3:
条件值 === 值3,需要执行的代码
break;
.......
default:
条件值和上面所有的case后面的值都不全等,则会执行这里的代码
break;
}
/**switch语句注意事项
* 1.表达式的结果要和值一定是全等的关系===
* 2.break作用:结束该switch语句,所以一般情况下要加上,如果不加上则会发生穿透
* * 穿透:从上一个case代码快执行到下一个case代码快
* * break关键字的作用就是防止穿透
* 3.default语句可以写在任何地方,也可以省略,但是一般写在最后,这是一种代码规范
*/
//示例:用户输入黑马学科编号,告诉用户学习什么学科 1-前端 2-PHP 3-java 4-UI
let subject= +prompt("请输入您要报名的学科编号,1-前端 2-PHP 3-java 4-UI");
switch (subject){
case 1:
alert("恭喜你选择了2020年最有钱途的学科!");
break;
case 2:
alert("选择了PHP,臭流氓!");
break;
case 3:
alert("选择了Java,请问植发多少钱一根?");
break;
case 4:
alert("未来的UI视觉交互设计师");
break;
default :
alert("脑子有包");
break;
}
</script>
</body>
</html>
switch-case穿透用法
- 合理穿透:多种值需要执行相同代码
<script>
/**合理穿透:当存在多种值需要执行相同代码时使用穿透可以节省代码
* 用户输入某一个月份,告诉用户这个月份属于什么季节
* 12,1,2 冬季
* 3,4,5 春季
* 6,7,8 夏季
* 9,10,11 秋季
*/
let month = +prompt("请输入月份");
switch (month){
case 12:
case 1:
case 2:
alert("冬季");
break;
case 3:
case 4:
case 5:
alert("春季");
break;
case 6:
case 7:
case 8:
alert("夏季");
break;
case 9:
case 10:
case 11:
alert("秋季");
break;
default:
alert("你来自火星吧?");
break;
}
</script>
三元表达式
1.运算符根据参与运算的值数量分为一元、二元、三元运算符
- 一元运算符:只能操作一个值 ++ — !
- 二元运算符:操作两个值 1 + 1 1 > 0
- 三元运算符:操作三个值
2.三元运算符语法
三元运算符:
?:
三元表达式:
表达式?代码1:代码2
- 1.如果表达式成立则执行代码1,否则执行代码2
2.如果代码1或者代码2有运算结果则三元运算式的结果就是他们其中的一个
三元运算符做的事和if-else类似,只是代码更简洁
三元表达式中:表达式部分永远是条件,最终代表整个结果的不是代码1 就是 代码2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script>
/*
一元运算符:由一个值参与的运算符 : a++ a-- !a
二元运算符: 由两个值参与的运算符 : a + b a > b
三元(三目)运算符:由三个值参与的运算符
*/
/*
* 三元运算符: ?:
* 三元表达式: 表达式?代码1:代码2
* * 1.如果表达式成立则执行代码1,否则执行代码2
* * 2.如果代码1或者代码2有运算结果则三元运算式的结果就是他们其中的一个
*
* 三元运算符做的事和if-else类似,只是代码更简洁
*/
//案例1:
let num1 = 10;
num1 > 0 ? console.log('哈哈') : console.log('呵呵');
//上面这个三元表达式等价于下面的if - else语句
// if(num1 > 0){
// console.log ( "哈哈" );
// }else{
// console.log ( "呵呵" );
// }
//案例2:三元表达式一般应用是用来赋值
let num2 = 20;
let res2 = num2 > 0 ? num2 + 1 : num2 - 1;
console.log ( res2 );//21
//上面这个三元表达式等价于下面的if - else语句
// if(num2 > 0){
// res2 = num2 + 1;
// }else{
// res2 = num2 - 1;
// }
//练习:输出性别 (实际开发中,性别通常会使用一个布尔类型来存储,这样存储效率更高)
let name = "马云";
let age = 38;
let gender = true; //true男 1 false女 0
console.log("我的名字是"+name+",我的年龄是"+age+",我是一个"+(gender == true ? "男":"女")+"生");
</script>
</html>
三种分支结构语法总结
- 1.原则上,三种分支结构语句之间可以互转,只不过每一种分支结构语句适用场景不一样
2.if分支结构:适合条件判断
- 最常用:if-else 两种互斥条件判断
- 3.switch-case 适合做固定值匹配
- 4.三元表达式: 比if-else代码更简洁,但是代码量较多时易读性变差
3-循环结构(3种语法)
循环结构作用:代码重复执行
while循环结构
- 1.语法:
while(条件 true/false){
循环体/需要重复执行的代码;
}
执行步骤:
1.判断条件是否成立
- 1.1 如果成立,执行循环体代码,然后重复步骤1
- 1.2 如果不成立,结束循环,执行大括号后面的代码
3.注意点
- (1)小括号中的语句,无论结果是什么都会转换成布尔类型来判断是否成立
- (2)避免写一个死循环
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//需求:打印 3 次 '我爱大前端'
//复制粘贴弊端:(1)代码冗余 (2)不便于维护
// console.log ( "我爱大前端" );
// console.log ( "我爱大前端" );
// console.log ( "我爱大前端" );
/*
1.循环结构 : 代码重复执行
2. 语法
while(条件 true/false){
循环体 :需要重复执行的代码
};
执行步骤
1. 判断条件是否成立
2.1 成立:执行循环体代码。 重复步骤1
2.2 不成立,循环语句结束,执行大括号后面的代码
*/
let i = 1;//循环变量,记录循环次数
while(i<=3){
console.log ( "我爱大前端" );
i++;////循环变量自增 自增的目的是为了控制循环的次数,否则这是一个死循环
}
console.log('111');//大括号外的代码与循环结构没有关系,还是顺序执行
//循环语句注意点:
//循环语句注意点:
//(1)小括号中的语句,无论结果是什么都会转换成布尔类型来判断是否成立
//(2)避免写一个死循环
//let num = 1;
// while(num < 10){
// console.log ( num );
// num++;//改变循环变量的值,可以避免死循环
// }
</script>
</body>
</html>
do-while循环结构
- 1.语法:
do{
循环体;
}while( 条件 );
2.执行过程
- 1.先执行循环体代码
2.执行条件语句
- 如果结果为true,执行循环体代码
- 如果为false,循环结束
- 3.重复步骤2
3.do-while和while实现的循环其实是一样的,只有一个不同点:do-while循环不管怎样先执行一次循环体代码,然后再判断条件
- while循环:先奏后斩(先判断条件再执行循环体)
- do-while循环:先斩后奏(不管怎样先执行一次循环体代码,然后再判断条件)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
/* 1. 学习目标 : do-while循环
2. 学习路线
(1)复习while语法特点
(2)学习do-while语法
(3)介绍do-while语法应用场景
*/
//1.while循环:
//let i = 1;
// while(i > 5){
// //循环条件不成立,循环体一次都不执行
// console.log ( "哈哈哈哈" );
// i++
// }
//2.do-while循环
/**
do-while语法:(用的很少)
do{
循环体;
}while( 条件 );
特点:无论如何先执行一次循环体,然后再去判断条件
*/
let i = 1;
do{
console.log ( "呵呵呵呵呵" );
i++;
}while (i > 5);
//while循环:先奏后斩(先判断条件再执行循环体)
//do-while循环:先斩后奏(不管怎样先执行一次循环体代码,然后再判断条件)
//3.do-while循环与while循环应用场景
//无论如何需要先执行一次循环体,使用do-while代码更简洁
//例子:让用户输入账号和密码,如果输入正确就登陆成功,如果输入错误就让他一直输入
//while循环实现
// let username = prompt('请输入账号');
// let password = prompt('请输入密码');
//
// while(username != 'admin' || password != '123456'){
// username = prompt('请输入账号');
// password = prompt('请输入密码');
// }
//do-while实现
do{
let username = prompt('请输入账号');
let password = prompt('请输入密码');
}while(username != 'admin' || password != '123456')
</script>
</body>
</html>
三种循环结构总结
- 1.原则上,三种循环结构语句之间可以互转,只不过每一种语句的适用场景不一样
- 2.最常用:for循环:适合循环次数固定
- 3.while循环:适合循环次数不固定
- 4.do-while循环:适合循环次数不固定,但是循环体代码至少要执行一次
4-数组排序-冒泡算法
- 算法algorithm,是一种解决问题的方法
- 算法的目标:使用最少的内存,最短的时间,解决最多的问题
冒泡算法:
重复地走访过要排序的元素列,依次比较两个相邻的元素
- 顺序正确:代表位置正确,不需要交换
- 顺序错误:交换两个元素,让顺序正确
<script>
/*
冒泡算法(顺序:从小到大)
1.从第一个元素开始,比较下一个元素
* 如果前面一个大于后面的元素:交换
* 如果前面一个小于或者等于后面的元素:不用动
2.循环比较数组中的每一个元素:直到最大的那个元素到达数组最后
3.一次循环,只能得出最大的数据排到最后,因此需要根据数组元素的长度来进行循环嵌套
* 一次只能让当前最大的到最后(如果原来最大的就在最后,那么就是次大的)
* 根据数组长度实现:每次都能得出一个最大,直到全部都排好序
*/
// 定义一个无序数组
let arr = [3,5,1,8,6,2];
// 外部循环:决定里面循环的次数
for(let i = 0;i < arr.length;i++){
// 内部循环:决定当前最大的元素跑到正确的位置去
for(let j = 0;j < arr.length - 1;j++){
// j < arr.length - 1 是因为需要进行向后一个进行元素匹配
// 判定当前元素与后一个元素的关系:前面大于后面:交换(其他情况不用变)
if(arr[j] > arr[j+1]){
// 交换两个元素的值:采用第三个变量
let temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
console.log(arr); // [1,2,3,5,6,8]
</script>
- 注意:上述是最复杂的冒泡算法,还可以进行优化
5.面向对象的概念
- 一种编程行业通用的写
项目级
的代码的思维 - 引导我们如何编写高质量的代码
万物皆对象 - 看待事物的角度
- 属性:数据
- 行为:动作(函数)
代码特点
- 封装
- 继承
6.思考题目为什么
const obj = {
name: "悟空",
skill: "变大变小"
}
let obj2 = obj;
obj2.name = "八戒";
console.log(obj); // 修改了obj2 为什么 obj也会发生改变
const name = "龙马";
let name2 = name;
name2 = "白骨精";
console.log(name);// 修改了name2 为什么name没有发生改变
7.栈和堆
栈(stack)中主要存放一些基本类型的变量和对象的引用其优势是存取速度比堆要快,但缺点是存在栈中的数据大小与生存期必须是确定的,缺乏灵活性,
堆(heap 多)用于复杂数据类型(引用类型)分配空间,例如数组对象、object对象;它是运行时动态分配内存的,因此存取速度较慢。
栈和堆的图例
8.创建对象的几种方式
字面量
- 简单粗暴
- 不适合创建多个同样类型的对象的场景
const obj ={ name:"悟空",height:100,age:5000};
工厂函数
容易理解
失去
血缘关系
,无法简单分辨对象的特征
function createPerson(name, age, height) {
return {
name: name,
age: age,
height: height
}
}
function createStudent(name, age, height, grade) {
return {
name1: name,
age1: age,
height1: height,
grade: grade
}
}
// 这个不是工厂模式
function createStudent2(name, age, height, grade) {
this.name = name;
this.age = age;
this.height = height;
this.grade = grade;
}
const obj1 = createPerson("八戒", 18, 500);
const obj2 = createStudent("悟能", 83, 231, 3);
const obj3 = new createStudent2("悟能", 83, 231, 3);
console.log(obj1);
console.log(obj2);
console.log(obj3);
构造函数
- 可以方便的创建对象
- 拥有血缘关系
- 还有后续更多的优势
// 1 声明函数
function createStudent(name, age) {
// 2 通过 this 赋值
this.name = name;
this.age = age;
}
// 3 通过 new 来创建对象
const obj = new createStudent("悟能", 83);
console.log(obj);
小结: 笔试题比较常见
构造函数的工作原理:
- 开辟空间
- 将新的创建的对象对象构造函数中的this
- 为对象赋值
- 将创建好的对象的地址返回
构造函数的弊端
同一个 say
方法占据了两份内存
function createStudent(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name);
}
}
const obj = new createStudent("悟能", 83);
const obj1 = new createStudent("悟能1", 84);
console.log(obj.say === obj1.say); // false 不是同一say方法 浪费了内存
图示
提取同一个 say
方法
- 解决了浪费内存的弊端
- 但是造成了
污染全局变量
的问题
// 提前将say 声明好
function say() {
console.log(this.name);
}
function createStudent(name, age) {
this.name = name;
this.age = age;
this.say = say
}
const obj = new createStudent("悟能", 83);
const obj1 = new createStudent("悟能1", 84);
console.log(obj.say === obj1.say); // true
图示