let和const命令:
let特点:
不能重复声明
块级作用域,指的是除 对象{} 以外,其它花都中使用let声明的变量都是某个作用域
const特点:
/* 某些值,从始至终不会变,那么建议使用常量。 PI、LN、E。推荐使用大写 程序中:URL地址、端口号。 const 声明常量 。一旦常量必须赋值。 */
字符串新增方法:
startsWith
语法:字符串.startsWidth( 参数字符 )
endsWith
描述:参数字符串是否在原字符串的尾部
ES6 引入了一种新的原始数据类型Symbol
,表示独一无二的值。
Symbol 值通过Symbol
函数生成。
代码案例应用场景:
常用来模拟对象私有属性和方法。
一般常用于框架、js内置函数和对象中
let sym2 = Symbol('age')
let obj = {
username:'zs',
sym1:20,
[sym2]:22 ,//以symbol的值当作key
}
// console.log( obj,'obj对象' )
console.log( obj[sym2] )//22
console.log( obj.sym1 )//20
console.log( obj[ 'sym1' ] )//20
数组新增方法:
Array.of
语法:Array.of( ...args )
代码案例:
/*
字面量 []
构造函数:new Array()
*/
// let arr1 = new Array( 3 )
// let arr2 = [3]
// console.log( arr1,'arr1',arr1[2] ) //3*undefined 有缺陷
// console.log( arr2,'arr2' ) //[3]
//es6 Array.of
let arr1 = Array.of( 3 )
let arr2 = Array.of( 33,22 )
console.log( arr1,'arr1' )//[3]
console.log( arr2,'arr2' )//[33,22]
Array.from
语法:Array.from( arrayLike ) 作用:把伪数组转换成数组,相对于ES5的写法,更加简洁方便
代码案例:
<button>30元</button><button>120元</button><button>50元</button>
<script>
/*
基本方法1:push pop concat shift unshift sort
有回调函数的方法:every forEach map some filter find findIndex
以上方法是数组对象调用的:因为这些方法在原型链上
es6提供了一些方法
Array.of()
Array.from()
*/
//1. Array.from( 伪数组 ) : 把伪数组转换成数组
//伪数组:和数组很相像,但不是数组,伪数组的原型链不指向Array
//arguments对象、选择元素集合、节点集合等都是伪数组
let btns = document.getElementsByTagName('button')
// console.log( btns )
// console.log( btns.forEach,'undefined' )
// btns.forEach( ) //forEach is not a function
//转数组
a = Array.from( btns )
console.log( a,'是个数组了' )
a.forEach(function(ele){
console.log( ele,'当前循环项' )
})
</script>
对象新增方法:
Object.keys
语法:Object.keys( object ) 描述:返回一个数组,成员是参数对象自身的属性的键名
Object.values
语法:Object.values( object ) 描述:返回一个数组,成员是参数对象自身的属性的键值
代码案例:
/*
Object.keys( 对象 ): 获取对象下的key,以数组形式返回
Object.values( 对象 ): 获取对象下的value,以数组形式返回
*/
let obj = { username: 'zs', age: 20 }
let keys = Object.keys( obj )
console.log( keys,'keys' )
let values = Object.values( obj )
console.log( values,'values' )
Object.assign
描述:对象的合并( 拷贝 ),将源对象(source),复制到目标对象 ( target )
//浅拷贝只拷贝了一层。
//Object.assign 只for...in了一层,没用上递归 。
//Object.assign( 目标对象,源对象1,源对象2,... ) //把源对象1,源对象2等等拷贝 到目标对象上
let obj1 = {
username:'猪八戒',
hobbies:['吃','喝','背翠兰'],
}
let obj2 = {}
Object.assign( obj2,obj1 )
// console.log( obj2,'obj2' )
obj2.username = 'zbj'
obj2.hobbies[1] = 'he'
console.log( obj2,'obj2' )
console.log( obj1,'obj1' )
JSON.parse
语法:JSON.parse( jsonstr) 描述:把json字符串转换成js对象
JSON.stringify
语法:JSON.stringify( object ) 描述:把js对象转换成json字符串
代码案例:
//JSON.parse/JSON.stringify
//重点要记住:json字符串中的key和里面字符串必须 是双引号,而且json字符串不应该有函数 。
//JSON.stringify 把js对象转换成json字符串 ,它会把对象中的函数会删除
//JSON.parse: 把json字符串转换成js对象
//1. JSON.stringify
let obj = { username: 'zs', age: 20 } //这是js对象
let jsonstr1 = JSON.stringify(obj)
// console.log( jsonstr1,'json字符串' ) //{"username":"zs","age":20}
//2. JSON.parse
let str1 = ` {"username":"zs","age":20} ` //把json字符串转换成js对象
// console.log( JSON.parse( str1 ) )//如果JSON.parse解析一个不是json字符串的值会报错。
: Unexpected token a in JSON at position 18
//3. 实现深拷贝有缺陷:函数会丢失。最没有问题的是 DeepCopy方法( 递归+浅拷贝 )
// JSON.parse( JSON.stringify( ) )
let obj2 = {
username: 'zs1',
age: 10,
fn: function () {
console.log('my is fn')
}
}
console.log( JSON.parse( JSON.stringify( obj2 ) ) )
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值
/*
数组结构:
1) 数组:有序的(下标)
2) 对象:无序的(无下标,由键和值组成)
*/
/*
es6为开发者提供了2个新的数据结构
set类似数组
map类似对象
*/
代码案例:
//set : 它和数组相似,是有一组数据组成,但是里面没有重复的值。我们经常会用它来实现数组去重,是个伪数组
// new Set( [数组] )
// console.log( typeof Set ) //function
//1. 得到一个set
let arr0 = [ 11,11,22,33,11,22,22,44 ]
let set1 = new Set( arr0 )
// console.log( typeof set1 ) //object
// console.log( set1 ) //{ 0:11 ,1:22 ,2:33,3:44,size:4 }
// console.log( set1[0] )
let arr1 = Array.from( set1 )
console.log( arr1 )
//去重封装
function UniqueArr( arr ){
let set = new Set( arr )
return Array.from( set )
}
常见方法
size 获取set集合的长度 add(值) 给集合添加值,返回新set delete(值) 删除某个值,返回布尔值,表示是否删除成功 has(值) 查询这个值是否时集合的成员,返回布尔值 clear() 清空集合,没有返回值
代码案例:
//new Set() 得到 一个set实例,原型链有一些方法,做为了解即可。
let arr0 = [ 11,11,22,33,11,22,22,44 ]
let set1 = new Set( arr0 )
// console.log( set1 )
//add(value) 添加值
set1.add( 44 )
set1.add( 55 )
//delete(value) 删除值
set1.delete( 11 )
// console.log( set1 )
//has() 是否有这个值
console.log( set1.has( 11 ) )//false
//clear() 清空
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
let persons = { username:'zs' }
let obj = {
[persons]:'使用对象当作键' //当用对象当作键,那么会自动转换字符串 。'[object Object]'
}
/*
obj = {
'[object Object]':'使用对象当作键' ,
}
*/
console.log( obj,'obj' )
console.log( obj['[object Object]'],'obj' )
常见用法:
//2. new Map( [ [key,value],[key,value],... ] )
let persons = { username:'zs' }
let map1 = new Map( [ [1,'number123'],['a','my is string'],[ persons,'使用对象当作key' ] ] )
// console.log( map1,'map1' )
/*
size
get(key) localStorage.getItem(key)
set(key,value) localStorage.setItem(key,value)
delete(key) localStorage.removeItem(key,value)
clear()
has(key)
*/
console.log( map1.get('a') )//'my is string'
map1.set(true,'my is boolean')
console.log(map1,'map1')
运算符表达式:
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
解构:解析(分析)结构 ,分析数组或对象的结构 赋值:为变量赋值 等号两边的结构需要一致才能解构并且为变量赋值
/* let [] = [] */
1.完全解构:
//1. 基本语法 // let arr = [ 10,20,11 ] //arr[0] arr[1] // let [ a,b,c ] = [ 10,20,11 ] // console.log( a,b,c ) //10,20,11
2.不完全解构:
//2. 不完全解构 . 值比变量多 // let [ b,c ] = [ 10,20,11 ] // console.log( b,c ) //10,20
3.解构失败:
//3. 解析失败。变量声明但未赋值,变量比值多 // let [ a,b,c ] = [ 10,20 ] // console.log( a,b,c ) //c:undefined
4.解构缺省
//4. 缺省 // let [ ,b,c ] = [ true,false,20 ] // console.log( b,c )//false 20
5.解构默认值:
//5. 默认值 // let [a, b, c = 111] = [10, 20,null] //没有相应的值赋值给c,所以默认值生效。如果有值则覆盖默认值 let [a, b, c = 111] = [10, 20] //没有相应的值赋值给c,所以默认值生效。如果有值则覆盖默认值 。 console.log(a, b, c) //c:111
数组解构应用(数据交换):
代码案例:
// let a = 10;
// let b = 20;
// let c = a;
// a = b;
// b = c;
let a = 10;
let b = 20;
[b,a] = [a,b];
console.log( a,b )
对象解构:
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,而对象的属性没有次序。
无序的:
/*
无序的
语法1:{ key2:变量名2,key1:变量名1 } = { key1:value1,key2:value2,... }
语法2(简写):{ key2,key1} = { key1:value1,key2:value2,... }
声明了key2和key1变量 值是右键对象中对应的键的值
*/
//1. 完整写法,完全的解构(每个属性中的值都赋值给了某个变量)
// let { username:uname,age:uage } = { age:20,username:'zs' }
//把右边对象中username中值给了变量uname,。。。。
// console.log( uname,uage )
//2. 简写写法
// let { username,age } = { age:20,username:'zs' }
// console.log( username,age )
//3. 默认值
let { username,age,sex='女' } = {sex:'男', age:20,username:'zs' }
console.log( sex ) //男
//4. 解构失败:变量未赋值
// let { username,age,sex } = { age:20,username:'zs' }
// console.log( sex ) //undefined
使用场景:
代码案例:
// function getStyle1( ele,attr ){
/*
let ele = 'width'
let attr = document
*/
// console.log( ele,'ele' )
// console.log( attr,'attr' )
// }
// getStyle1( 'width',document )
function getStyle2( {ele,attr} ){
/*
let {ele,attr} = { ele:document,attr:'height' }
*/
console.log( ele,'ele' )
console.log( attr,'attr' )
}
getStyle2( { attr:'height',ele:document } )
多层解构:
/*
多层解构的补充-了解
*/
let person = {
username: 'zbj',
hobbies: ['吃', '喝']
}
// console.log( person.hobbies[1] )
let { hobbies: [, a] } = person
console.log(a, 'a-----')
代码案例:
//rest是获取函数的剩余参数,间接的可以获取所有参数 。
//es6的rest是为了代替es5中的arguments。
//rest是个数组,而arguments为伪数组
//无论有无具体的实参,rest永远是个数组
//1. arguments
// function fn1(){
// console.log( arguments,'arguments' )
// }
// fn1( 2,3,5 )
//2. 获取所有参数
// function fn2( ...rest ){ //rest名称只要符合变量名规范即可
// console.log( rest ) //...前面没有其它参数,则获取了所有参数
// }
// fn2( 2,3,5,7 )
//3. 获取剩余参数
function fn3( a,b,...rest ){
console.log( a,b )
console.log(rest)
}
//fn3( 11,22,33,44,55 ) //11=>a 22=>b [33,44,55 ]=>rest
fn3( ) // [ ]=>rest
函数传参:
//1. 展开数组形式的实参。了解即可, 调用函数实参如果是数组可以展开,对象不能在此处展开
// function fn1( a,b,c ){
// console.log( a,b,c )
// }
// fn1( 1,2,3 )
function fn1( a,b,c ){
console.log( a,b,c )
}
// fn1( ...[10,20,30] ) //fn1( 10,20,30 )
// console.log( ...[11,22,33] )
//1. 实现浅拷贝
// let obj1 = {
// username:'zs',
// hobbies:[ 11,22,33 ]
// }
// let obj2 = { ...obj1 } //实现的浅拷贝
// // console.log( obj2 )
// obj2.username = 'ls'
// obj2.hobbies[0] = 10
// console.log( obj1,'obj1' )
//2. 数组合并
// concat
let arr1 = [ 10,20 ]
let arr2 = [33,44]
let arr3 = [ ...arr2,...arr1 ]
// console.log( arr3,'arr3' ) //[33, 44, 10, 20]
//3. 伪数组转数组
let set1 = new Set( [11,22,33,11,22,33,33] )
// console.log( set1 )
// console.log( [ ...set1 ] )
//三种伪数组转数组:Array.from Array.prototype.slice.call( 伪数组 ) [ ...伪数组 ]
参数特性:
/*
形式变了:语法变了。箭头函数,写法上更加简洁。
形参、返回值、this指向
(形参列表)=>{
函数体
return 返回值
}
*/
没有参数:
//1. 定义一个基本的箭头函数,使用变量声明的方式
// let fn1 = ()=>{
// console.log('my is fn1')
// }
// fn1() //先声明后使用
多个参数:
//2. 形参的扩展
//2.1 多个参数
// let fn2 = ( a,b,c )=>{
// console.log( a,b,c )
// }
// fn2( 11,22,33 )
一个参数:
//2.2 只有一个形参,小括号可以省略
// let fn3 = (a)=>{
// let fn3 = a =>{
// console.log( a )
// }
// fn3(111)
有返回值:
//3.1 完整写法return
let fn4 = ()=>{
return 10
}
// console.log( fn4() )
//3.2 如果有返回值,且函数内只有1行代码那么return可以省略,同时也要把花括号省略
let fn5= ()=>20
// console.log( fn5() )//20
let fn6= a=>a*a
// console.log( fn6(5 ) ) //25
//3.3 返回对象的问题
let fn7 = ()=> ( { age:20,sex:'男' } ) //把对象使用小括号包起来。
console.log( fn7() )
//1. 不做为构造函数
let fn1 = ()=>{
}
// new fn1() // fn1 is not a constructor
// function fn3( a,b,c = 11 ){
// console.log( a,b,c ) //c:11
// }
let fn3 = (a,b,c = 12)=>{
console.log( a,b,c )
}
// fn3( 10,20 ) //c:12
fn3( 11,22,33 ) //c:33
//2. 箭头函数无arguments
let fn2 = ( ...rest )=>{
console.log( rest )
}
// fn2( 11,22 ) //[ 11,22 ]
/*
call/apply bind 事件 new 普通函数调用/回调:window
箭头函数和以上通通没有关系
箭头函数无this指向,它里面的this指的是上层环境( script全局、function )的this
*/
//3.1 普通调用
let fn4 = ()=>{
console.log( this,'fn4' )
}
// fn4( ) //window
//3.2 事件调用
document.onclick = ()=>{
console.log( this,'事件调用' ) //window
}
//3.3 扩展一下
function Person(){
//this = new Object()
let fn = ()=>{
console.log( 'fn',this )
}
fn()
}
// Person() //this=> window
// new Person() //this=> person的实例对象
Person.call( document ) //this=> document
就应用在回调函数中,写法上更加简洁,其它形式上:事件还是普通的function!
let obj = {
prices:[ 100,300,200 ],
num:10,
sum:function(){
//console.log( this,'obj' )
// let _this = this
// let ps = this.prices.map( function(item){
// // console.log( this )
// return item * _this.num
// } )
let ps = this.prices.map((item)=>{
// console.log(this)
return item * this.num
} )
console.log( ps,'ps' )
},
}
obj.sum()
/*
已知函数A,函数B
函数B传递到A中,B在A中执行的。此时B是A的回调
*/
类calss:
代码示例:
/*
class 类名{
....定义属性
....定义方法
}
*/
//1. class定义类
class Person {
//1.1 定义属性
username = 'ls'
age = 18
fn2 = () => { //不推荐此写法
console.log('fn2', this)//p1
}
//1.2 定义方法 //放在原型上
fn1() {
console.log('fn1', this) //p1
}
}
//2. 实例化1
// let p1 = new Person()
let p1 = new Person // 如果不传参,小括号可以省略
// console.log( p1,'p1' )
p1.fn1()
p1.fn2()
对比ES5和ES6实现对象/类:
代码案例:
//es5方式问题:方法和属性是整体(封装性),但是它分开了。
function Person(username,age){
this.username = username
this.age = age
}
Person.prototype.say = function(msg){
console.log( this.username + '说了一句:' + msg)
}
// let p1 = new Person( 'zs',20 )
let p1 = new Person
p1.say( 'say hello' )
class Person{
//constructor 内置函数名
constructor( username,age ){ //就是做一些初始化工作的:比如为属性进行赋值
/*
每实例化一次,此函数就会调用一次,无需手动调用
*/
//console.log('con执行了',this)
this.username = username
this.age = age
}
}
let p1 = new Person( 'zs',15 )//这里的实参给了constructor的形参
console.log( p1,'p1' )
// new Person
let p2 = new Person( 'ls',16 )
console.log( p2,'p2' )
代码示例:
/*
私有的:
指属性和方法属于对象的。
在类中定义的属性和方法都属于私有的
静态的:公共的
指属性和方法属于类的或者说属于函数的。
static关键字指定静态
什么时候用私有的、什么时候用静态的?
张三:在上学的踏上捡了100元
smoney = 100
班费、班级名称可以设置为公共的(静态的)
*/
class Student{
static CNAME = 'WEB1013' //静态属性,类直接就能访问到,对象不能访问
constructor(username){
this.username = username //私有属性,只能实例化出来的对象访问
}
//在类中定义一个私有方法
getClassName(){
// return '1012web'
return Student.CNAME
}
}
// console.log( Student.username )//undefined
// console.log( Student.CNAME )//WEB1012
let xm = new Student('xm')
// console.log( xm,'xm' )
// console.log( xm.CNAME )//undefined
console.log( 'xm的班名为:',xm.getClassName() ) //1012web
let zs = new Student('zs')
console.log( 'zs的班名为:',zs.getClassName() ) //1012web
extends
代码案例:
class Person{
constructor(username){
console.log(username,'父类----')
this.username = username
}
say(){
console.log('say function')
}
}
//extends 扩展、继承的意思
class Student extends Person{ //即实现了属性继承,又实现原型上的方法继承
// xuehao = 1111
constructor(username,xuehao){
//如果子类中书写了constructor,则必须在最前面写 super()
super(username) //子类就是调用父类的constructor
//console.log(username,'子类-----')
this.xuehao = xuehao
}
zzy(){
console.log(this.username + '我能做作业')
}
}
let stu1 = new Student('小明','0002') //如果 子类没写constructor,则参数直接传递给父类的constructor。
//如果写了肯定传给子类的constructor
console.log( stu1,'stu1' )
代码案例:
<script>
//class模拟JavaScript等一系列的对象
//我们扮演的角色是使用对象 。
//数组对象、字符串对象、数学对象、时间对象、定时器对象、正则对象、地址栏对象、历史记录对象,学的函数
class JS {
Math(){
return {
ceil(){
console.log('向上取整方法')
},
round(){
console.log('四舍五入方法')
}
}
}
Date(){
}
}
let j = new JS()
let ma = j.Math()
// console.log( ma )
ma.ceil()
ma.round()
</script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$.prototype.aa = 'my is aa'
let t = $() //$是个构造函数
// console.log( typeof t )//object: jquery对象
// console.log( t )//object: jquery对象
console.log( t.aa )//原型链继承
</script>
简介:
迭代、循环、遍历、递归等可以称为循环。
以前的循环方式:
for / for in / while / do...while .. $.each forEach map ....
正是因为以前的遍历方式太混乱,所以es6统一了 遍历,for…of。掌握for…of遍历即可。
作用:
使得数据结构的成员能够按某种次序排列 ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of使用 Iterator是一个抽象的概念, 具体的实现 for...of / Symbol.iterator
代码案例:
<script>
//字符串 、数组、伪数组(set/map/元素集合)等等。唯独对象不能使用for...of
/*
for( let val of 要遍历的数据 ){
}
*/
//1. 遍历字符串
// let str = 'abcde'
// for( let val of str ){
// console.log( val ) //a b c d e
// }
//2. 遍历数组
// let arr = ['11',22]
// for( let v of arr ){
// console.log(v,'--') //11 22
// }
//3. 遍历set
// let set1 = new Set( [11,22,33,11,22,33] )
// for( let v of set1 ){
// console.log( v,'set1' )
// }
//4. 唯独对象不能使用for...of
let obj = { useranme:'abc' }
for( let v of obj ){ //obj is not iterable ,对象不是一个可遍历的数据
console.log( v,'sdf' )
}
</script>
注意事项:在使用for…of遍历数据时, 要确保被遍历的数据, 拥有Iterator功能
原生具备iterator接口的结构有:
数组、伪数组(set/map/元素集合)等等。唯独对象不能使用for...of
原理分析:
//for...of遍历数据时, 要确保被遍历的数据, 拥有Symbol.iterator
//比如我们分析数组
let arr = [11,22]
//console.log( arr )
//console.log( typeof arr[Symbol.iterator])//function
let iterObj = arr[Symbol.iterator]() //指针对象的原型链上 有一个next方法。
//console.log( iterObj,'指针对象' )
let value1 = iterObj.next()
console.log( value1,'value1' ) //{ value:11,done:false }
let value2 = iterObj.next()
console.log( value2,'value2' ) //{ value:22,done:false }
let value3 = iterObj.next()
console.log( value3,'value3' ) //{ value:undefined,done:true }
// let obj = { useranme:'abc' }
// console.log( obj )
往对象身上加 Symbol.iterator即可。
<script>
let obj = { useranme: 'zs', age: 20,sex:'男' }
//Symbol.iterator是个函数
obj[Symbol.iterator] = function () {
let aa = Object.values( obj ) //获取对象所有的值以数组返回
// console.log( aa,'aa' )
let index = 0
return {
//a:123
next:function(){
if( index >= aa.length ){
return { value:undefined,done:true }
}else{
return { value:aa[index++],done:false }
}
}
}
}
for( let val of obj ){
console.log( val,'val' )
}
// let iterObj = obj[Symbol.iterator]()
// //console.log( iterObj )
// console.log( iterObj.next() ) //{ value:zs,done:false }
// console.log( iterObj.next() )
// console.log( iterObj.next() )
</script>