一.JavaScript的组成:
1.ECMAScript:JavaScript的基本语法
2.BOM:浏览器对象模型(操作浏览器)--核心对象window
3.DOM:文档对象模型(操作html文档)--核心对象document
二.ECMAScript
1.ECMAScript5:脚本语言。不需要独立的编译器,通过浏览器加载运行,实现用户和页面的交互。
2.ECMAScript6:是JavaScript的下一代语法标准,于2015年6月发布。是JavaScript正式成为企业级的开发语言
3.ECMAScript和JavaScript的关系:
ECMAScript是一个语法规范,JavaScript是改语法规范的实现
三.ES6的语法
1.let和const
(1)let:用来声明块级变量。var声明的变量会出现作用域的提升(会出现变量的污染)
(2)const:声明的常量必须要初始化
(3)const声明的对象:
<script>
const p = {
name:'张三',
age:18,
family:{
son:"美羊羊",
daughter:'懒羊羊'
}
}
</script>
a.可以修改对象的属性值,但是不能修改对象本身
<script>
const p = {
name:'张三',
age:18,
family:{
son:"美羊羊",
daughter:'懒羊羊'
}
}
p.name = '李四'
console.log(p)
</script>
b.冻结对象:不能修改对象的属性。使用object.freeze(对象名)
<script>
const p = {
name:'张三',
age:18,
family:{
son:"美羊羊",
daughter:'懒羊羊'
}
}
Object.freeze(p)//冻结对象obj,就不能修改obj的属性
p.name = '李四'
console.log(p)
</script>
c.冻结嵌套的对象hasOwnProperty(key)函数:判断key是否是对象的属性,若是返回true,不是返回false
<script>
const p = {
name:'张三',
age:18,
family:{
son:"美羊羊",
daughter:'懒羊羊'
}
}
// 定义一个冻结函数
function fun(obj){
// 1.冻结对象:参数接收的对象
Object.freeze(obj)
// 2.使用for……in循环遍历对象的属性
for(let key in obj){
// hasOwnProperty()用来判断对象是否包含给定的属性。typeof用来判断数据类型
if (obj.hasOwnProperty(key) && typeof obj[key] === 'object') {
fun(obj[key])
}
}
}
fun(p)
p.family.son = '懒羊羊'
console.log(p)
</script>
四.ES6的新特性
1.临时死区:用let和const声明的变量,放在临时死区,使用let声明的变量、const声明的常量的作用域不会被提升
2.在循环中使用var的情况:
<script>
// {
// console.log(typeof a)
// var a = 10
// }
let arr = []
for (var i = 0; i < 5; i++) {//var定义的i是全局变量;如果将var改为let
arr.push(function(){//arr是一个函数数组:数组的每个单元都是函数
console.log(i)//5 5 5 5 5;则输出0 1 2 3 4
})
}
arr.forEach(function(item){//item是函数
item()
})
// let t = [11,23,45,67]
// t.forEach(function(item){
// console.log(item)
// })
</script>
3.解构赋值:Rest运算符:“…”
(1)当迭代使用:会按顺序遍历容器中的元素
<script>
function fun(x,y,z){
console.log(x,y,z)
}
let arr = [11,34,56]
fun(arr[0],arr[1],arr[2])
fun(...arr)//'...'运算符的作用是一个迭代器:依次遍历数组中的元素
</script>
(2)替代函数的内置属性arguments
<script>
function fun(...args){
console.log(args)
}
arr = [11,34,56]
fun(arr)
// function fun(){
// console.log(arguments)
// }
</script>
(3)通过Rest运算符(...)可以简化变量的赋值
<script>
let arr1 = [11,22,33]
let [a,b,c]=arr1
// 或
// let [a,b,c]=[10,20,30]
console.log(a)
console.log(c)
</script>
(4)通过'...'把特定的元素放在变量里
<script>
let [a1,...arr2]=[11,22,33]//将11赋给a1,22、33赋给arr,arr是一个数组
console.log(a1)
console.log(arr)
</script>
(5)通过解构来交换变量的值
<script>
let a2 =10;
let b2 = 20;//必须以';'结尾
[a2,b2]=[b2,a2]
console.log(a2,b2)
</script>
4.对象的解构
(1)将对象的属性解构出来赋给变量
<script>
let obj = {
id:1001,
name:'懒羊羊',
sex:'男'
}
let {id,name,sex}=obj//变量名必须和对象的属性名相同
console.log('编号:',id)
console.log('姓名:',name)
console.log('性别:',sex)
</script>
(2)解构多层对象
<script>
let obj1 = {
id1:1002,
name1:'暖羊羊',
sex1:'女',
score:{
html:66,
js:77,
css:88
}
}
let {id1,name1,sex1,score:{html,js,css}}=obj1
console.log('编号:',id1)
console.log('姓名:',name1)
console.log('性别:',sex1)
console.log('html:',html)
console.log('js:',js)
console.log('css:',css)
</script>
(3)在解构时可以给变量取别名
<script>
let obj2 = {
id1:1002,
name1:'暖羊羊',
sex1:'女',
score:{
html:66,
js:77,
css:88
}
}
let {id1:userId,name1:userName}=obj2
console.log(userId)
console.log(userName)
</script>
5.模板字符串:使用反引号``和${变量名}将字符串常量和变量写在一个串里。就不需要使用'+'进行字符串的拼接
6.Symbol类型
(1)ES5的数据类型:number、string、Boolean、bigint、null、undefined、object
(2)ES6新增的Symbol:表示一个唯一的值
a.直接创建
<script>
let s1 = Symbol
let s2 = Symbol
console.log(s1 == s2)//true
</script>
b.间接创建:传字符串 let 变量名 = Symbol(字符串)
<script>
let a1 = Symbol('abc')
let a2 = Symbol('abc')
console.log(a1 === a2)//false
let obj = {
a1:'asd',
a2:'aqw'
}
</script>
7.Set集合:是一种数据结构,里面不能存放重复的值。可以用于数组去重、字符串去重
(1)创建方式:
a.使用new运算符: let 变量名 = new Set()
<script>
let s1 = new Set()//创建一个空集合
console.log(s1)
</script>
b.通过数组来创建:let 变量名 = new Set([1,2,34,6,5,4,3,2,6,4]),去除重复的元素
<script>
let arr = [1,2,34,6,5,4,3,2,6,4]
let s2 = new Set(arr)
console.log(s2)
</script>
(2)常用的方法
a.add(val):向集合中添加元素
<script>
let tep = s1.add('table')
console.log(typeof tep)
s1.add(123).add(456).add('abc')
console.log(s1)//Set(4) {'table', 123, 456, 'abc'}
console.log(...s1)//table 123 456 abc
console.log([...s1])//将集合转换成数组(4) ['table', 123, 456, 'abc']
</script>
b.delete(val):删除集合中的元素。删除成功返回true,否则返回false
<script>
let flag = s1.delete(123)
console.log(flag)
console.log([...s1])
</script>
c.has(val):判断val在集合中是否存在,若存在返回true,否则返回false
<script>
let f = s1.has('table')
console.log(f)
</script>
d.clear(val):清空集合
<script>
s1.clear()
console.log(s1)
</script>
e.values():获取的是集合中所有value
<script>
let t = s1.values()
console.log('values:',t)
</script>
f.keys():获取集合中key
<script>
let k = s1.keys()
console.log('keys:',k)
</script>
强调:Set集合的结构也是key-value格式,它的key和value是相同的
(3)属性:size存放的是集合中元素的个数
<script>
console.log('Size:',s1.size)
</script>
(4)遍历方法:
a.for ... of
<script>
for (let i of s1.values()) {//s1.values()也可以写成s1
console.log(i)
}
</script>
b.forEach
<script>
s1.forEach(function(value,key){
console.log(value+'----'+key)
})
</script>
(5)集合运算
a.并集:
<script>
let set1 = new Set([12,3,4,2])
let set2 = new Set([2,3,45])
// 1.实现set1与set2的并集(去除重复)
let bj = new Set([...set1,...set2])
console.log(bj)//Set(5) {12, 3, 4, 2, 45}
</script>
b.交集:
<script>
let set1 = new Set([12,3,4,2])
let set2 = new Set([2,3,45])
// 2.实现set1与set2的交集:通过过滤器实现
// [...set1]解构集合set1,将其转换成数组
let t = [...set1]
// console.log(t)
// 对t进行过滤:使用filter函数
let t1 = t.filter(function(item){//依次从t中取出元素传递给item,在函数体内设置筛选条件,将满足条件的元素赋给t1
return set2.has(item)//将满足条件的item返回
// 上下等价
if (set2.has(item)) {
return item
}
})
console.log(t1)
</script>
c.差集:
<script>
let set1 = new Set([12,3,4,2])
let set2 = new Set([2,3,45])
// 3.差集
// [...set1]解构集合set1,将其转换成数组
let t = [...set1]
// 对t进行过滤:使用filter函数
let t1 = t.filter(function(item){//依次从t中取出元素传递给item,在函数体内设置筛选条件,将满足条件的元素赋给t1
// return !set2.has(item)
//上下等价
if (set2.has(item) == false) {
return item
}
})
console.log(t1)
</script>
8.WeakSet:只能一个对象集合。即集合中只能存放对象。它支持add、delete、has方法
<script>
let obj1 = {
name:'cc',
age:18
}
let ws = new WeakSet([{'a':23}])
ws.add(obj1)
console.log(ws)
console.log(ws.has())
ws.delete(obj1)
console.log(ws)
</script>
练习:
定义一个构造函数Student,包含id、name、html、css、Javascript 5个属性,利用该构造函数创建5对象并存入数组arr中。然后对数组进行如下操作:
(1)利用该构造函数创建5对象,并将这5个对象存放到Set集合中
(2)把css成绩不及格的对象挑选出来
<script>
function fun(id,name,html,css,js) {
this.id = id
this.name = name
this.html = html
this.css = css
this.js = js
}
let s1 = new fun('01','懒羊羊',67,56,78)
let s2 = new fun('02','灰太狼',64,54,88)
let s3 = new fun('03','慢羊羊',66,66,68)
let s4 = new fun('04','小灰灰',45,53,79)
let s5 = new fun('05','喜羊羊',78,36,89)
//集合
let newa = new Set()
newa.add(s1).add(s2).add(s3).add(s4).add(s5)
console.log(newa)
//不及格
// 方法一
for (const key in newa) {
if (newa[key].css<60) {
console.log(newa[key])
}
}
// 方法二:过滤器
let arr = [...newa]
let temp = arr.filter(function(item){
if (item.css < 60) {
return item
}
})
console.log(temp)
</script>
五.Map集合
1.数据的存放格式:采用key=value的方式进行存放。采用这种方式存放数据的有
(1)对象:属性对应的是key(键),属性值对应的是value(值)
<script>
let obj = {
name:'懒羊羊',
age:18
}
</script>
(2)JSON:是常用的一种前后台数据交换的格式
(3)Map的定义:Map是一种数据结构(Hash结构),在ES6中Map是一种存放许多键值对的有序列表
3.Map的使用方法
(1)属性:size --- 存放的是Map中的元素个数
(2)方法:
a.Map():构造方法。用来创建Map对象,不带参数表示创建空的Map,size属性为0
<script>
let map1 = new Map()
console.log('map的长度:',map1.size)//0
</script>
b.set(key,value):向Map中添加数据
<script>
map1.set('name','懒羊羊')
map1.set('CHN','中国')
map1.set('US','美国')
map1.set('CAN','加拿大')
console.log(map1)
console.log('map的长度:',map1.size)
</script>
c.get(key):获取键为key的value
console.log(map1.get('CHN'))
d.has(key):判断Map中是否存在key
console.log(map1.has('US'))
e.delete(key):删除key
console.log(map1.delete('US'))
f.clear():清空Map()
g.keys():返回Map中的所有key
console.log(map1.keys())
练习1.以'key<===>value',显示一个Map
<script>
let map = new Map()
map.set('id', '1001')
map.set('name', '懒羊羊')
map.set('age', 18)
for (const key of map.keys()) {
// key<===>value 键值对
let str = `${key}<===>${map.get(key)}`
console.log(str)
}
</script>
强调:
(1)Map中的key不能重复
(2)keys()返回的是Map中所有key集合 --- keys()返回的集合类型是Set
(3)在Map中可以通过key可以得到对应的value,反之则不行
h.values():返回Map中的所有value
for (const val of map.values()) {
console.log(val)
}
i.entries():可以获取Map的所有成员(即所有的key-value)
for (const temp of map.entries()) {//.entries()可以不写
console.log(temp)
}
// or
for (const [key, value] of map.entries()) {
console.log(`${key}:${value}`)
}
j.forEach()循环遍历:
map.forEach(function (value, key) {//第一个参数是value,第二个是key
console.log(`${key}:${value}`)
})
练习2:Map数组(数组的每个单元都是key-value)的使用
<script>
let mapp = new Map([
['one', '懒羊羊'],
['two', '暖羊羊'],
['three', '喜羊羊'],
['four', '美羊羊'],
])
console.log(mapp)
let map1 = new Map()
map1.set('one', '懒羊羊')
map1.set('two', '羊羊')
let map2 = new Map()
map2.set('three', '羊')
let map3 = new Map()
let arr = [map1, map2, map3]
console.log(arr)
// 找出懒羊羊
console.log(arr[0].get('one'))
</script>
4.Map转换为数组
(1)解构整个Map:
<script>
let map = new Map([
['one', '懒羊羊'],
['two', '暖羊羊'],
['three', '喜羊羊'],
['four', '美羊羊'],
])
let arr = [...map]//将map转换成数组:4行2列的二维数组
console.log(arr)
</script>
(2)解构keys()
let a = [...map.keys()]//将Map中所有的key转换为数组
console.log(a)
(3)解构values()
let b = [...map.values()]//将Map中所有的value转换成数组
console.log(b)
六.函数
1.ES5中的函数:
(1)通过function关键字定义函数
function 函数名(【参数】){}
(2)函数表达式
let 变量名 = function(【参数】){}
注意: (1)形参和实参的区别
(2)函数的返回值:return语句来实现
2.ES6中对函数的扩展
(1)函数参数的默认值
<script>
function fun(a,b,c=45) {//形参c默认值45,如果调用时没有给c传递参数,则使用默认值
if (typeof a === 'undefined') {
a = 65
}
// 判断是不是采用默认值
if (typeof b === 'undefined') {
b = 46
}
console.log('a=',a)
console.log('b=',b)
console.log('c=',c)
}
//第一种调用:直接调用
fun(1,2,3)
//第二种调用
let a = 10,b=20;
fun(a,b)
</script>
(2)箭头函数:在定义函数时使用‘=>’符号。在定义回调函数(高阶函数)、函数表达式时使用。可以简化代码
<script>
//1.函数没有参数,函数体语句只有一条
let fun1 = ()=> '🐇'
console.log(fun1())
let fun2 = ()=>{return '🐇'}
console.log(fun2())
//当箭头函数的函数语句只有一条时,需要注意两点:
//(1){}可以省略
//(2)默认有return,
//2.函数带有一个参数,可以省略'()'
let fun3 = args => {//args是形参
console.log(args)
}
fun3(1024)//函数调用,将1024传递给形参args
//3.函数带有多个参数
let fun4 = (a1,a2)=>a1+a2
//等价于
//let fun4 = (a1,a2)=>{return (a1+a2))}
console.log(fun4(2,3))
// 4.函数体只有一条语句,函数返回对象:必须用'()'将对象包起来
let fun5 =()=>({
name:'懒羊羊',
age:18
})
console.log(fun5())
//5.箭头函数中this绑定
window.id=1002
let obj = {
id:1001,
fun6:function(){
console.log(this.id)//this代表obj
},
fun7:()=>{
console.log(this.id)//输出undefined,在箭头函数中没有绑定this,this指向离它最近的上层对象(window)
}
}
obj.fun6()//1001
obj.fun7()//undefined
//6.箭头函数没有内置的arguments
/*
let pt =()=>{
console.log(arguments)//报错
}
pt(12,23)// arguments is not defined
*/
let btn = document.querySelector('#btn')
btn.addEventListener('click',()=>{
alert('1111111')
})
</script>
七.类
1.面向对象:是一种开发思想,一切皆为对象。对象是属性和行为的结合体
2.面向过程:也是一种开发思想。开发中的每个细节,开发者都要考虑到。
3.类:具有相同属性和行为的对象的集合
4.ES5中实现类的功能:构造函数,在构造函数中封装了属性和方法。缺陷是构造函数和普通函数的定义方法是一样的
5.ES6中类的定义方式:语义性更强、语法更简洁
class 类名{
属性
行为(方法)
}
class是关键字,专门用来定义类。
<script>
// 1.用class定义Student类
class Student{
constructor(id,name,sex){//构造函数。this后面的id、name、sex是属性
this.id=id
this.name=name
this.sex=sex
}
display(){
console.log('id=',this.id)
console.log('name=',this.name)
console.log('sex=',this.sex)
}
}
// 2.使用Student类创建对象:创建对象时,不能显示的使用constructor,必须用类名创建,默认调用的是类的constructor函数
let s1 = new Student(101,'懒羊羊','男')
let s2 = new Student(102,'暖羊羊','女')
let s3 = new Student(103,'潇洒哥','男')
// 3.使用对象
s1.display()
console.log('------')
s2.display()
console.log('------')
s3.display()
</script>
练习1:
(1)定义一个Book类,包含ISDN、author、publish、price4个属性,包含show()方法:用于显示图书信息
(2)定义一个数组,在数组中存储了5个book对象,遍历数组,输出price最高的book对象
(3)将数组中的5个对象显示在html页面的table中
<body>
<table border="1">
<thead>
<tr>
<th>Isdn</th>
<th>author</th>
<th>publish</th>
<th>price</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script>
class Book{
constructor(ISDN,author,publish,price){
this.ISDN = ISDN
this.author = author
this.publish = publish
this.price = price
}
show(){
console.log('ISDN:',this.ISDN)
console.log('author:',this.author)
console.log('publish:',this.publish)
console.log('price:',this.price)
}
}
let b1 = new Book(1001,'小灰灰','111',34)
let b2 = new Book(1002,'冰心','222',44)
let b3 = new Book(1003,'鲁迅','333',24)
let b4 = new Book(1004,'高尔基','444',45)
let b5 = new Book(1005,'懒羊羊','555',23)
b1.show()
b2.show()
b3.show()
b4.show()
b5.show()
// 2.定义数组
let arr=[b1,b2,b3,b4,b5]
// for (let i = 0; i < arr.length; i++) {
// arr[i].show()
// }
// 假设第一个价格最高
let max = arr[0]
for (let key in arr) {
if(max.price<arr[key].price){
max = arr[key]
}
}
console.log(max)
// 3.table
let tbody = document.querySelector('tbody')
for (let i = 0; i < arr.length; i++) {
let tr= document.createElement('tr')
tbody.appendChild(tr)
for (let key in arr[i]) {
let td = document.createElement('td')
tr.appendChild(td)
let txt = document.createTextNode(arr[i][key])
td.appendChild(txt)
}
}
</script>
</body>
6.ES6中支持getter/setter来获取属性值、设置属性值
(1)定义get方法、set方法的目的是:用于隐藏对象的属性名
(2)在使用get方法、set方法时不用带'()'
<script>
class Account{
constructor(id,pwd){
this._id = id//加'_'的属性,称为私有属性(是语义上的区分)
this._pwd = pwd
}
// 1.定义get方法:获取属性的值
get id(){
return this._id
}
get pwd(){
return this._pwd
}
// 2.定义set方法:设置属性值
set id(value){
this._id = value
}
set pwd(value){
this._pwd = value
}
}
let a1 = new Account('1001','123456')
console.log('账号:',a1.id)//a1.id实际调用的是id()方法
console.log('密码:',a1.pwd)//a1.pwd实际调用的是pwd()方法,因为pwd()方法前有get,因此调用时不用带'()'
console.log('--------------------------')
a1.id = '1002'//实际调用的是set id(value)方法
a1.pwd = '111111'//实际调用的是set pwd(value)方法
console.log('账号:',a1.id)
console.log('密码:',a1.pwd)
</script>