一、初始JavaScript
JavaScript 是 Web 的编程语言。
所有现代的 HTML 页面都使用 JavaScript。
在网页中,JavaScript 代码,需要在script标签中定义。
script标签可以放在的网页的任何地方,但是,通常会放到body标签的最下方,
确保JavaScript 代码,在网页的内容全部加载完毕后再执行。
1.输出语句
console.log 输出信息
console.warn 输出警告信息
console.error 输出错误信息
console.table 以表格的方式展开对象的成员信息
console.time(name) 开始测试时间
console.timeEnd(name) 结束测试时间
2.定义变量
1.什么变量
就是内存中的一个空间,用于存储数据,数据的种类是不一样的,所以对空间的要求也不一样。
定义不同类型的变量,其实就是定义不同的存储空间,存储不同的数据。
var是定义变量的关键字,定义变量的方式是:var 变量名 = 变量值。
变量名就是变量的标识,用于之后重新获取变量里面保存的值。
注意:js是一门弱类型语言,不像java,C#是强类型语言。
强类型语言,在定义变量的时候,就必须要明确类型,并且之后不能再改变类型。
弱类型语言,在定义变量的时候,不需要明确类型,类型由具体的数据确定,并且之后可以改变类型。
2.类型
number是数字类型,注意:在js中,整型和浮点型的数据都是number类型。
string是字符串类型,由一对双引号 或 单引号 引起来的数据都是字符串。
boolean是布尔类型,布尔类型用于表示:真 或 假。只有两个属性值:true 和 false。
undefined是未定义类型,变量已经定义,但是还没有赋值。
object是对象类型,用于定义复杂的数据格式。
null是空类型,用于表示空对象,所以,null本质上也是object类型,但是不具有object默认的属性和行为。
symbol是ES6新增了一个数据类型,用于确定一个唯一的数据,通常用于给对象添加唯一的属性 或 方法。
ES6指的是ECMAScript2015之后的版本
注意:在js中,每条语句采用分号结尾,分号可以省略。
总结:在js中,数据类型一共有7个。
分别是:number(数字类型),string(字符串类型),boolean(布尔类型),undefined(未定义类型),
object(对象类型),null(空对象类型),symbol(唯一值类型)。
3.算术运算符
算术运算符:+ - * / %
注意:字符串 + 任何数据 都是拼接,重新返回新的字符串。
表达式是从左往右执行,当遇到字符串时,整个表达式才当做字符串处理。
除法运算,除法会保留小数。
parseInt()函数,用于取整数,注意:并不是四舍五入,而且去掉小数。
简写形式:
b += a //b = b + a
b -= 10 //b = b - 10
b *= 2 //b = b * 2
b /= 5 //b = b / 5
b %= 3 //b = b % 3
num++ // num = num + 1
++num // ++可以放在变量的后面,也可以放在变量的前面
++在变量的后面,表示先返回变量的原值,再加1
++在变量的前面,表示变量的值先加1,再返回变量的值
4.比较运算符
比较运算符:> >= < <= == != ===(全等于,恒等于) !==(恒不等于)
使用比较运算符的表达式是比较表达式,比较表达式返回的数据类型是boolean类型
注意:采用==比较两份数据是否相等,只比较值,不比较类型。
注意:采用===比较两份数据是否相等,值要相等,类型也要相等。
注意:采用!=比较两份数据是否不相等,只比较值,不比较类型。
注意:采用!==比较两份数据是否不相等,值不相等或者类型不相等。
5.逻辑运算符
逻辑运算符:&&(并且) ||(或者) !(取反)
|| 是或运算符,左右两个表达式,其中一个返回true,整个表达式返回true
&& 是与运算符,左右两个表达式,都返回true,整个表达式才返回true
! 是非运算符,用于将表达式的值取反值,如果表达式返回true,取反就是false
6.运算符的优先级
运算符的优先级:() > 算术运算符 > 关系运算符 > ! > && > ||
7.命名规范
变量里面保存的是一份数据,为了方便将来获取里面存储的数据,变量名命名一定要规范。
就是看到变量名就知道里面存储的是什么数据。(见名知意)
在JS中,变量名的规范有:
只能使用:字母、数字、_、$ 做为变量名称。
数字不要开头
不能使用JS的关键字
多个单词组成的变量名,要使用驼峰命名法,第一个单词的首字母小写,其余单词的首字母大写。
二、选择结构
1.JavaScript的组成
1.三大核心
ESMAScript 核心语法(标准规范)-> SE6
BOM 浏览器对象模式,其实就是window对象,该对象可以操作浏览器
DOM 文档对象模型,其实就是document对象,该对象可以操作网页里面的所有元素
2.window对象的常用方法
alert()方法,用于打开消息框
prompt()方法,用于打开输入框,输入框返回的数据的类型是string类型
confirm()方法,用于打开确定框,确认框里面有两个按钮,确定和取消,点击确定按钮返回true,点击取消按钮返回false
parseInt()方法,用于将字符串数据,强转为整型
parseFloat()方法,用于将字符串数据,强转为浮点型
isNaN()方法,用于判断一份数据是不是NaN数据(not a number)
2.if选择结构
if选择结构的语法是:if(判断条件){满足条件之后,执行的代码块}
if-else选择结构,if()里面的条件成立执行if{}里面的代码块,否则执行else{}里面的代码块
注意:当if或者else里面只有条件语句的时候,可以省略{}
建议:初学者,不要省略{}
3.多重if选择结构
多重if选择结构里面,满足其中一个条件,执行该条件对应的代码,执行完成后跳出整个程序结构。
如果所有的条件都不成立,有else,就执行else;没有else,整个程序结构结束。
4.嵌套if选择结构
嵌套if选择结构:就是在一个完整的if或者else的结构中,继续使用if结构语句。
练习题:
请输入是否是会员,输入y是会员,输入n不是会员
请输入消费金额
会员:消费打8折,满100元打6折
非会员:消费满200元打9折,不满200元不打折
最后输出本次实际消费金额
多重if和嵌套if的综合练习题:
输入年 月 输出该月份有多少天?
闰年公式:年份能被4整除,但不能被100整除;或者年份能被400整除。闰年的2月份是29天,平年的2月份是28天。
5.switch选择结构
switch选择结构,也是用于进行多分支判断,语法结构比多重if简洁。
但是,switch选择结构只能进行等值判断。
语法结构是:将需要进行等值判断的变量,放到()里面。在{}里面通过case后面的值跟它进行等值判断。
注意1:case语句,在结束之前,通常都要加上break,表示跳出switch选择结构,因为,
switch选择结构,里面的case一旦判断成立,后面的case就不会再进行判断了。
注意2:如果多个case的输出结果相同,可以将多个case的结果合并,并省略前面case的break。
6.三元运表达式
三元表达式,可以简化基本的if-else语句结构
var c = a > 10 ? 100 : 200
三元表达式,也可以简化复杂的if-else语句结构
var e = a > 20 ? 200 : (a > 10 ? 100 : 300)
三、循环结构1
1.var let const
使用var关键字定义的变量,变量名可以重复,后面的变量会将前面的变量覆盖掉。
var方式定义变量,会统一提升到全局作用域的顶端定义,然后再指定的地方赋值。
var定义的变量,即使在指定的代码块中,仍然会提升到全局作用域的顶端。
因为使用var定义变量,存在上面的各种问题,所以从ES6开始,又引入的新的方式定义变量
使用let,在同一个作用域中,不能定义同名的变量。
let定义的变量,不存在提升。
const关键字,用于定义常量,常量的特点是:不能重新赋值,并且在定义时,必须要赋值。
2.模板字符串
使用 '' 和 "" 定义的数据是字符串数据
console.log('大家好!我叫'+name+',今年'+age+'岁,性别是'+gender+',职业是'+job);
在ES6中,又加入 `` ,在反引号里面,可以定义模板字符串,方式是${变量名}
console.log(大家好!我叫${name},今年${age}岁,性别是${gender},职业是${job}
);
如果字符串采用""包裹,里面可以定义''
如果字符串采用''包裹,里面可以定义""
如果希望我们定义的字符串中,既包括双引号,又包括单引号,过去是采用转义字符的方式定义的。
转义字符串:" 表示 " ' 表示 '
console.log("'大家好'!"才是真的好"!");
现在可以直接在模板字符串中使用双引号和单引号
console.log('大家好'!"才是真的好"!
);
转义字符的其他用法
\t 表示水平制表符,其实就是一个Tab键
\n 表示换行符,其实就是一个Enter键
\ 表示一个\
3.while循环
//()里面是循环的条件,条件成立,执行{}里面的操作
while(条件){
操作
}
练习题1:找出100以内,能被3整除的数,并输出
练习题2:找出21世纪里面所有的闰年,并打印出来
练习题3:输入年 月 日,算出该日期是全年的第多少天
4.do-while循环
do{
操作
}while(条件)
while循环的特点是:先判断条件,再执行循环操作
do-while循环的特点是:先执行一次循环操作,再判断循环条件
所以,do-while循环,没有入口判断,无论循环条件是否满足,至少会执行一次循环体
练习题1:系统菜单:输入 1.添加学生,2.修改学生,3.查询学生,4.删除学生,0.退出系统
练习题2:小型ATM机系统
四、循环结构2
1.for循环
for(条件变量;循环条件;迭代部分){
操作
}
for循环,就是由while循环演变而来
在for循环,可以将循环的条件变量,判断条件,对象循环变量重新赋值,放在一起,好处是不容易遗漏任何一部分
for循环结构中的循环变量可以定义多个
while,do-while,for,如何选择:
当循环的次数是固定的时候,通常使用for循环
当循环的次数不固定的时候,通常会使用while和do-while循环
2.循环的跳出语句(continue,break)
在循环结构中break,表示跳出整个循环
在循环结构中continue,表示跳出本次循环
五、多重循环
在二重循环中,外层循环变量变化一次,内层循环变量变化整个
练习题1:有三个班级,每个班级有四名学生,输入所有学生的成绩,并计算出每个班级的平均分
练习题2:打印直角三角形
练习题3:打印倒直角三角形
练习题4:打印等腰三角形
练习题5:打印99乘法表
练习题6:数字等腰三角形
练习题7:找出100以内所有的质数
在内层循环中,使用continue,break,只是作用于内层循环
练习题1:有5家店,每家店最多可以买3件衣服,进入一家店后,提示是否离开本店,
输入y表示离开(会进入下一家店),输入n表示买一件衣服,最后输出用户一共买了多少件衣服。
作业
鸡兔同笼:有25个头,94只脚,请问鸡和兔各多少只
百钱买百鸡:公鸡5文钱一只,母鸡3文钱一只,小鸡1文钱3只,请问公鸡母鸡小鸡各多少只
打印菱形
打印空心菱形
六、字符串和数组
1.字符的常用方法
length属性,返回的是字符串的长度
charAt()方法,根据字符串中字符的索引(下标)获取对应的字符,注意:索引从0开始
获取字符串的中指定索引的字符,也可以通过[索引]的方式获取
charCodeAt()方法,用于获取字符串中指定位置字符的Unicode编码值
什么是Unicode编码,不同国家的人,使用不同的字符描述数据,这些字符计算机不认识
计算机只认识二进制数字,也就是0和1,所以将全世界范围内使用的常用字符都定义一个对应的十进制数字编码
而这个十进制的数字编码就是Unicode编码,再将这些十进制的Unicode编码转为二进制编码传给计算机识别
比如:A -> 65 a -> 97 你 -> 20320
concat()方法,用于拼接字符串,通常情况下,我们可以直接使用 加号 去拼接,该方法,可以同时拼接多个字符串数据
fromCharCode()方法,用于将指定的Unicode编码转为指定字符,注意该方法是有String类型来调用的,该方法,可以传递多个Unicode编码
indexOf()方法,用于从字符串中返回指定字符串第一次出现的位置(注意:索引从0开始,找不到返回-1)
lastIndexOf()方法,是从后往前找,找到后,下标是从前往后数(注意,如果找不到返回-1)
slice()方法,用于截取指定区间范围内的字符串,该方法需要传两个参数,分别是起始位置和结束位置,能够取到起始位置,取不到结束位置,注意:slice()方法的参数,可以传负数,表示从后往前数索引
substring()方法,用于截取指定区间范围内的字符串,该方法需要传两个参数,分别是起始位置和结束位置,能够取到起始位置,取不到结束位置,注意:substring()方法参数,只能传正数,不能传负数
substr()方法,也是用于截取字符串,它的两参数分别是:起始位置和截取长度
注意:slice,substring,substr方法,如果只传1个参数,就表示从起始位置到最后全部截取
toLowerCase()方法,用于返回字符串转的小写版本,注意:不是改自身
toUpperCase()方法,用于返回字符串的大写版本,注意:不是改自身
trim()方法,用于去除字符串两端空格
2.字符串练习题
输入邮箱地址,验证邮箱格式是否正确
输入登录名和密码,要求登录名长度为2-4位,密码长度是6-10位,用户名不能是全数字
输入手机号码,要求长度必须是11位,第一位必须是1,后面的必须是数字
3.数组
变量:就是在内存中,开辟一个合适的空间,存储一份对应的数据
数组:就是在内层中,开辟一段连续的空间,存储一组数据
创建数组的第一种方式,使用数组的构造函数,new一个数组类型的对象
let arr1 = new Array(5)
创建数组的第二种方式:使用字面量方式直接定义
let arr2 = ["hello","world"]
length属性,返回的是数组的长度
根据数组的下标(索引),向数组中存放数据,数组中可以存放任意类型的数据
注意:在创建数组对象时,可以给一个固定的长度,但是没有意义,因为在js中数组的长度是可以随意变化的
4.数组的常用方法
concat()方法,用于合并两个或多个数组,返回一个全新的数组
copyWithin()方法,从数组的指定位置拷贝元素到数组的另一个指定位置中
注意:第一个参数是目标位置,第二个参是拷贝元素的起始位,第三个参数是拷贝元素的结束位置
如果不设置第三个参数,拷贝元素结束位置就是目标位置的前一位
fill()方法,使用一个固定值来填充数组
includes()方法,从数组中检查指定的数据是否存在,存在返回true,不存在返回false
indexOf()方法,从数组中检查指定的数据的位置(从前往后找第一个),不存在返回-1
lastIndexOf()方法,从数组中检查指定的数据的位置(从后往前找第一个),不存在返回-1
isArray()方法,用于检查指定的对象是否是数组,注意:该方法属于Array类型,不属于Arrary的对象
join()方法,用于将一个数组根据某个字符串拼接成字符串,该方法不传参数,默认是根据逗号拼接
push()方法,向数组的末尾添加一个或更多元素,并返回新的长度
pop()方法,删除数组的最后一个元素并返回删除的元素
unshift()方法,向数组的开头添加一个或更多元素,并返回新的长度
shift()方法,删除并返回数组的第一个元素
reverse()方法,反转数组的元素顺序
slice()方法,选取数组的一部分,并返回一个新数组
注意:该方法的第一个参数是起始位置,第二个参数是结束位置(取不到结束位置)
第二个参数可以省略,表示从起始位置到最后全部返回
splice()方法,从数组中添加或删除元素
如何删除,该方法需要传两个参数:第一个是起始位置,第二个是删除长度
如果第二个参数不传,就表示从起始位置往后全部删除
删除方法,删除的是原始数组里面的数据,返回的是删除的数据
该方法也可以传三个参数,第三个参数就是删除部分插入的新内容
repeat(num) 方法,用于重复指定的字符串多少次
toString()方法,把数组转换为字符串,并返回结果
5.数组练习题
如何反转字符串
先将字符串转为数组,再将数组反转,然后将反转后的数组,再转为字符串
学生管理系统
定义四个数组,分别存储学生的学号,姓名,年龄,性别
七、Math和Date
1.排序算法
sort()方法,用于对数组排序
注意:该排序方法,是根据数组中,每一个元素首字符的unicode编码进行排序的
手写排序算法:
冒泡排序算法
选择排序算法
2.Math对象
Math对象 里面提供的方法,可以帮助我们解决算术问题
提供的方法:
Math.random() 返回一个0到1之间的随机数
abs() 返回一个数的绝对值
ceil() 向上取整
floor() 向下取整
max() 返回最大值
min() 返回最小值
pow() 返回指定数的次幂
round() 四舍五入
PI属性,返回圆周率
3.Date对象
创建并返回系统当前日期
let date1 = new Date()
在创建日期对象时,可以传递一个时间戳参数
时间戳:是从1970-1-1开始的毫秒数
let date2 = new Date(123456789)
也可以根据一个指定的时间,返回一个日期对象
let date3 = new Date('2011-1-1 12:12:12')
提供的方法:
getFullYear() 返回年份
getMonth() 返回月份 返回的值是0-11(0表示1月份,11表示12月份)
getDate() 返回月份的日期
getDay() 返回星期几 返回的值是0-6,(0表示星期天)
getHours() 返回小时 返回的值是0-23(0表示凌晨12点)
getMinutes() 返回分钟
getSeconds() 返回秒
getMilliseconds() 返回毫秒
getTime() 返回时间戳
getXXX方法用于获取时间对象中指定的部分
setXXX方法用于设置时间对象中指定的部分
练习题:计算两个日期相差多少天,注意:两日期对象相减,返回的是两个日期时间戳相减后的值
八、函数
1.定义
function 是定义函数的关键字,函数也称为方法
函数分为:
无参函数
带参函数
带返回值的函数
定义函数
function fn(形参) {
方法体
}
调用函数
fn(实参)
2.实现字符串函数
将字符串身上的常用函数,手动实现一遍
3.实现数组的函数
将数组身上的常用函数,手动实现一遍
4.定义函数的几种方式
第一个方式:通过function关键字直接定义
第二种方式:定义一个变量,接收定义的函数
ES6又推出了定义函数的简写方式,俗称:箭头函数
在箭头函数中,如果方法体只有一条语句,可以省略{}
在箭头函数中,如果方法只有一个参数,可以省略()
在箭头函数中,如果方法体只有一条语句,并该语句是返回语句,那么在省略{}的同时,必须省略return关键字
5.定义几个工具方法
检查一个年份是否是闰年
对个位数字补零
返回一个日期的短日期格式
返回一个中国式的日期格式
对字符串反转
6.递归方法
什么是递归方法:就是一个方法,自己调用自己
注意:递归方法,一定要控制好合适跳出,否则就是死循环
练习题1:计算1-20之间所有数之和
function calc(num){
if(num===1){
return num
}
let sum = num + calc(num-1)
return sum
}
练习题2:实现系统菜单
function menu(){
let no = parseInt(prompt('1.添加学生,2.修改学生,3.删除学生,0.退出系统'))
switch(no){
case 1:
alert('执行添加学生')
menu()
break;
case 2:
alert('执行修改学生')
menu()
break;
case 3:
alert('执行删除学生')
menu()
break;
default:
return //表示退出方法
}
}
九、高阶函数
什么是高阶函数:就是一个函数的参数是函数,或者返回值是函数,满足其中一个就是高阶函数
开闭原则:对扩展是开发的,对修改是封闭的
1.定义计算器方法
function calc(num1,num2,callback){
callback(num1,num2)
}
2.回调函数
输出数组中所有的数
输出数组中所有的奇数
输出数组中所能被3整除的数
分析问题:都用到了for循环
定义一个通用的for方法:
function bingFor(arr,callback){
for(let i=0;i
console.log(arr[i]);
}
}
}
3.数组的高阶方法
forEach()方法,用于循环遍历整个数组
该方法的参数是一个回调函数,回调函数可以传两个参数,第一个参数是数组中的每一项元素,
第二个参数是每一项元素对应的下标。
注意:第二个参数可以省略。
filter()方法,用于过滤数组中的元素,返回过滤结果
find()方法,用于获取数组中满足规则的第一个元素
findIndex()方法,用于获取数组中满足规则的第一个元素下标
some()方法,用于表示数组中是否有满足指定规则的元素,有返回true,一个都没有返回false
every()方法,用于表示数组中是否所有元素都满足指定的规则
map()方法,用于将原始数组里面的数据根据指定的规则返回新的数组
sort()方法,对数组的元素进行排序
回调函数需要传两个参数,返回参数1-参数2是升序,返回参数2-参数1是降序
reduce()方法,统计数组中元素的值(从左到右)
reduceRight()方法,统计数组中元素的值(从右到左)
4.闭包函数
定义一个a方法,在a方法中定义一个b方法,并且b方法里面用到了a方法里面定义的变量,
那么此时就形成了闭包函数
由于内部方法里面,用到外部方法里面的变量,外部方法里面的那个变量会一直在内存中存保存着
总结:两个方法嵌套定义,里面的方法,用到了外面方法里面定义的变量,此时这两个方法就形成了闭包。
闭包案例:计算机
function calc(n1, n2, type) {
// 数据定义在函数里面,用参数传值,保证了数据的安全性
let num1 = n1
let num2 = n2
switch (type) {
case '+':
return function () {
console.log(`${num1}+${num2}=${num1 + num2}`);
}
case '-':
return function () {
console.log(`${num1}-${num2}=${num1 - num2}`);
}
}
}
十、函数其他
1.实现数组的高阶函数
2.arguments
arguments对象里面保存这方法的所有参数
arguments对象里面有个一个callee方法,该方法指向当前方法本身
定义稳定的递归函数:
function calc(num){
if(num===1){
return num
}
// 因为arguments.callee 就时 指向当前方法本身。
// 这样的做的好处是,防止外部方法名修改后,导致递归调用失效。
let sum = num + arguments.callee(num-1)
return sum
}
3.分页方法
//定义一个分页方法,方法的三个参数分别是:原始数组,页码,每页数量
function pageData(arr,pageIndex,pageSize){
//思路:就是对原始数组中的数据,做截取
//定义截取数据的起始位置
let start = (pageIndex-1)*pageSize
//定义截取数据的结束位置
let end = start+pageSize
return arr.slice(start,end)
}
十一、对象
如果 a.b ,那么a就是对象,b是a的属性
如果 a.c(),那么a就是对象,c是a的方法
对象就是拥有一组属性和方法的集合
定义对象有两种方式:1.采用字面量赋值方式直接定义。2.采用构造函数的方式new一个对象
1.采用字面量赋值方式定义对象
let obj = {
//定义属性
//定义方法
}
通过对象名.属性,调用对象的属性,可以获取属性的值,也可以修改属性的值,也可以添加新的属性
通过对象名.方法(),调用对象的方法,执行方法里面的代码
案例:定义计算器对象,实现加减乘除。
2.采用构造函数的方式new一个对象
可以直接new一个Object对象
let obj = new Object()
可以定义一个构造函数,再出new这个构造函数的对象
构造函数也称为:类,是自定义的一种类型
//定义学生类
function Student(形参...){
//定义属性(必须使用this.)
//定义方法(必须使用this.)
}
//创建学生对象
let s1 = new Student(实参...)
十二、对象进阶
1.this
构造函数里面的this,用于给类定义成员(属性和方法)
方法里面的this,指向方法的调用者
箭头函数中没有this,如果在箭头函数中使用了this,会向外层寻找this的指向
如果所有的外层都没有this,最终会指向window对象
注意:用于var定义的成员(变量和方法)都会成为window对象的成员
解决this指向问题:
方式一:备份this
方式二:使用箭头函数
2.call apply bind
call apply bind 更改方法里面this的指向
使用call()改变方法里面,this的指向
call()方法的第一个参数必须是指定的对象,方法的原有参数,挨个放在后面
使用apply(),也可以改变方法里面this的指向,第一个参是指定的对象,方法的原有参数,统一放到第二个数组参数中。
使用bind(),也可以改变方法里面this的指向,用法给call()一样
call()是直接运行方法,bind()是返回新的方法,然后再重新调用。
3.将一个对象转为字符串
获取对象的属性值,有两种方式:
对象名.属性名
对象名["属性名"]
//定义一个手机对象
let phone = {
name: "小米10",
color: '红色',
size: '1000200500',
price: '2999'
}
//转成下面的字符串
//"name=小米10&color=红色&size=1000200500&price=2999"
for in 循环,可以循环出对象里面的所有的key,(key就是属性名)
在ES6中新增了获取对象所有key的方法 -> ECMAScript2015 其实就是最新版本的javascript标准
Object.keys(指定的对象),该方法可以获取指定对象的所有key,返回值是一个数组
Object.values(指定的对象),该方法可以获取指定对象的所有的value,返回值是一个数组
4.将字符串转为对象
//定义一个字符串
let str = "name=小米10&color=红色&size=1000200500&price=2999"
//转成一个对象
{
name: "小米10",
color: '红色',
size: '1000200500',
price: '2999'
}
5.封装js库
isLeepYear 判断是否闰年
strReverse 字符串翻转
getMiniDate 短日期
getChineseDate 中国式日期
getPageData 分页方法
getStrByObj 对象转字符串
getObjByStr 字符串转对象
6.试一试
统计字符串中每个字符串出现的次数
let str = "fasdfsadfsegsageqwgersfdhrhdfsergterwhefweteqheq"
//转成下面格式的对象
{
a:5,
b:7,
c:9,
...
}
找出出现次数最多的字符
//定义一个对象接收结果
let max = {
name:'',
count:0
}
十三、对象数组
十四、ES6补充
1.常用面试题
2.自执行方法
定义一个自执行函数,函数定义完成后,自己执行一次,函数名可以省略,因为没有任何意义
注意:要以分号结束,否则可能会影响后面的语句。
(function sayHello() {
console.log('sayHello');
})();
自执行函数的简写形式
- function sayYes() {
console.log('sayYes');
}();
自执行函数,也可以直接定义成箭头函数
(()=>{
console.log('aaa');
})()
3.rest参数
// ...args 就是rest参数
function fun1(a,b,c,...args){
console.log(a,b,c);
// arguments 是一个类数组对象,结构长得像数组,其实是一个object对象
console.log(arguments);
// rest参数 是一个数组对象,既然是数组,就可以直接使用数组的方法。
console.log(args);
}
4.展开运算符
展开运算符就是...,可以将一个数组全部展开
let arr3 = [...arr1,...arr2]
展开运算符,可以展开对象的全部成员,也可以将一个对象的成员,克隆给另一个对象
let lh2 = {...lh}
展开运算符,可以将多个对象的成员,合并到一个大的对象中,后面对象中的成员,如果跟前面对象中的成员同名,会覆盖前面的
let lxt = {...lh,...gxt}
5.解构赋值
ES6中的解构赋值语句,可以直接将数组中的每个元素提取出来
方式是:let [变量名1,变量名2,...] = 数组
ES6中的解构赋值语句,可以直接将对象中的每个元素提取出来
方式是:let {name,age,gender,job} = obj
通常情况下,对象的属性名称叫什么,就定义什么名称的变量去接,如果出现了同名,可以修改名称
方式是:let {name,age:age1,gender,job} = obj
在ES6中,定义对象时,属性的左右两边的表达式相同时,可以省略右边的表达式,该对象在定义的时候,会自动往父级作用域寻找同名属性名对应的值
十五、类和对象进阶
1.值类型和引用类型
在js中,number,string,boolean,都是值类型,值类型的变量,直接将数据保存到内存的栈空间中。
值类型的变量,在传递时,传的是副本。
在js中,对象,数组,都是引用类型,引用类型的变量,将数据保存在堆中,然后将堆的地址保存到栈中。
2.原型对象
prototype属性是类的原型对象
通常情况下,我们习惯将类的方法,定义到类的原型对象中,这样做的好处是,提高代码的利用率,不会开辟多余的内存空间。
proto属性是对象的原型对象,注意:同种类型多个对象上的原型对象 共同指向 类型上的原型对象。
类的原型对象上面的方法,类的对象,可以直接调用
3.ES6中定义类的新语法
// 定义一个Person类型
class Person{
// 构造函数
constructor(name,age,gender){
this.name = name,
this.age = age
this.gender = gender
}
// 给类添加一个方法
sayHi = function(){
console.log(this.name,this.age,this.gender);
}
//用这种方式定义的方法,是将方法定义的类的原型对象中去
sayHello(){
console.log('hello!');
}
}
4.继承
ES5:
// 定义一个人类
function Person(name, age, gender) {
this.name = name
this.age = age
this.gender = gender
}
Person.prototype.eat = function () {
console.log(我叫${this.name},我在吃饭...
);
}
Person.prototype.say = function () {
console.log(大家好!我叫${this.name} 今年${this.age}岁 性别是${this.gender}
);
}
// 通过Person类型,创建出了两个对象
let p1 = new Person('刘德龙', 20, '男')
p1.say()
p1.eat()
let p2 = new Person('高德政', 21, '男')
p1.say()
p1.eat()
console.log('-------------------------------------');
//定义了学生类
function Student(name, age, gender, no) {
// 继承Person类的属性
Person.call(this, name, age, gender)
// Student类特有的属性
this.no = no
}
// 给Student类的prototype属性 new一个Person类型的对象
// 用于继承Person类的方法
Student.prototype = new Person()
Student.prototype.study = function () {
console.log(我叫${this.name},我的学号是${this.no},我在学习...
);
}
let s1 = new Student('张三', 20, '女', '1001')
s1.study()
s1.eat()
s1.say()
ES6:
// 定义人类
class Person {
// 定义构造函数
constructor(name, age, gender) {
this.name = name
this.age = age
this.gender = gender
}
// 说话方法
say() {
console.log(大家好!我叫${this.name} 今年${this.age}岁 性别是${this.gender}
);
}
// 吃方法
eat() {
console.log(我叫${this.name},我在吃饭...
);
}
}
// 每个类型都一个prototype属性,我们称它为类的原型对象。
// 类的原型对象上面的成员,给类的所有实例(实例就是类创建出来的对象)共享。
console.log(Person.prototype);
// 通过Person类型,创建出了两个对象
let p1 = new Person('刘德龙', 20, '男')
console.log(p1);
p1.say()
p1.eat()
let p2 = new Person('高德政', 21, '男')
console.log(p2);
p1.say()
p1.eat()
console.log('-------------------------------------');
// extends关键字,表示继承
class Student extends Person{
// 构造函数
constructor(name, age, gender,no){
// 调用父类的构造函数
super(name, age, gender)
// 学生特有的属性
this.no = no
}
//学生学习的方法
study(){
console.log(我叫${this.name},我的学号是${this.no},我在学习...
);
}
}
let s1 = new Student('张三', 20, '女', '1001')
console.log(s1);
s1.study()
s1.eat()
s1.say()