一.let
作用:同var一样用来声明变量
特点
在块级作用域内有效
不能重复声明
变量提升
全局变量提升:会创建一个变量对象(script)用来收集全局作用域下let定义的变量
局部变量提升:会将var let定义的变量全部放到当前函数的变量对象中
同var的变量提升的区别:let提升的变量在为赋值之前不允许被使用
应用
循环遍历加监听
使用let取代var是趋势
二.const关键字
作用:定义一个常量
特点:不能修改,其他特点同let
应用:保存不用改变的数据
三.解构赋值
理解:从对象或数组中提取数据,并赋值给变量(多个)
对象的解构赋值
let {n,a} = {n:“tom” , a:12}
数组的解构赋值
let {a ,b} = {1 ,2}
用途:给多个形参赋值
四.模板字符串
作用:简化字符串的拼接
写法:模板字符串必须使用`` 包含,变化部分用 ${xxxx}定义
let obj = {username: 'kobe', age: 43};
let str = '我的名字是: ' + obj.username + ', 我的年龄是: ' + obj.age;
console.log(str);
console.log('---------------模板字符串拼接--------------------');
let str1 = `我的名字是 ${obj.username}, 我的年龄是 ${obj.age}`
console.log(str1);
五.对象的简写方式
同名属性可以省略–>key和value一样的时候
省略函数的function,冒号
let username = 'kobe';
let age = 43;
console.log('---------------- 对象的常规书写方式---------------------');
let obj = {
username: username,
age: age,
showName: function () {
console.log(this.username);
}
}
console.log(obj);
obj.showName();
console.log('---------------- 对象的简写方式---------------------');
let obj = {
username, // 同名的属性可省略 ---> key 和value一样的时候
age,
showName() { // 省略函数的function,冒号
console.log(this.username);
}
}
console.log(obj);
obj.showName();
六.箭头函数
语法:
let fun = 形参 => 函数体
重点:函数体
只有一条语句或者表达式的时候,{ }可以省略
当多条语句时候,{ }不能省略
当{ }省略的时候,会自动return当前语句或者表达式的执行结果
特点:
理解:
定义的时候看外部是否有函数,如果没有函数,this指向window
如果有外部函数,this同外部函数的this指向是同一个对象
箭头函数不能用作构造函数
console.log('------------- 箭头函数 - 没有形参 -----------------');
// 当箭头函数没有形参的时候 () 不能省略
let fun = () => console.log('fun()');
fun();
console.log('------------- 箭头函数 - 有一个形参 -----------------');
// 当箭头函数只有一个形参的时候,() 可以省略,也可以不省略
let fun1 = a => console.log('只有一个形参的时候', a);
fun1(123);
console.log('------------- 箭头函数 - 有多个形参 -----------------');
// 当箭头函数有多个形参的时候, ()不能省略
let fun2 = (a, b) => console.log('有多个形参的时候', a, b);
fun2(1,2);
console.log('------------- 箭头函数 - 函数体只有一条语句的时候 -----------------');
// 当箭头函数的函数体只有一条语句的时候{}可以省略, 当{}省略的时候会自动 return 当前语句或者表达式的结果, 当{}不省略的时候,需要手动指定返回的结果, 否则默认执行 return value: undefined;
let fun3 = () => console.log('函数体只有一条语句的时候');
console.log(fun3());// 语句的返回结果,undefined
let fun3 = () => 123
console.log(fun3());//表达式的返回结果,123
console.log('------------- 箭头函数 - 函数体有多条语句的时候 -----------------');
// 当箭头函数的函数体有多条语句的时候,{}不能省略, 当{}不省略的时候,需要手动指定返回的结果, 否则默认执行 return value: undefined;
let fun4 = () => {
let a = 1;
console.log('函数体有多条语句的时候', a);
// return a;-->1
}
console.log(fun4());//undefined
七.点点点运算符
1 …运算符去拆包指定的数组
//把arr2数组插入到arr里面1和6中间
let arr = [1, 6];
let arr2 = [2,3,4,5];
let arr3 = [1, ...arr2, 6];
console.log(arr3); // [1, 2, 3, 4, 5, 6]
2 …运算符去拆包不能直接去遍历对象
let obj2 = {name: 'kobe', age: 43};
console.log(...obj2);//报错
八.Symbol
前言:ES5中对象的属性名都是字符串,容易造成重名,污染环境
概念:ES6中的添加了一种原始数据类型symbol(已有的原始数据类型:String, Number, boolean, null, undefined, 对象)
特点:
1、Symbol属性对应的值是唯一的,解决命名冲突问题
2、Symbol值不能与其他数据进行计算,包括同字符串拼串
3、for in, for of遍历时不会遍历symbol属性
let symbol = Symbol();
let obj = {};
obj[symbol] = 'hello';
2、传参标识
let symbol = Symbol('one');
let symbol2 = Symbol('two');
console.log(symbol);// Symbol('one')
console.log(symbol2);// Symbol('two')
3、内置Symbol值
* 除了定义自己使用的Symbol值以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法。
- Symbol.iterator
* 对象的Symbol.iterator属性,指向该对象的默认遍历器方法
九.Iterator遍历器(迭代器)
概念: iterator 是一种接口机制,为各种不同的数据结构提供统一的访问机制
作用:
1、为各种数据结构,提供一个统一的、简便的访问接口;
2、使得数据结构的成员能够按某种次序排列
3、ES6创造了一种新的遍历命令 for…of循环,Iterator接口主要供for…of消费。
工作原理:
- 创建一个指针对象(遍历器对象),指向数据结构的起始位置。
- 第一次调用next方法,指针自动指向数据结构的第一个成员
- 接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
- 每调用next方法返回的是一个包含value和done的对象,{value: 当前成员的值,done: 布尔值}
* value表示当前成员的值,done对应的布尔值表示当前的数据的结构是否遍历结束。
* 当遍历结束的时候返回的value值是undefined,done值为false
原生具备iterator接口的数据(可用for of遍历)
1、Array
2、arguments
3、set容器
4、map容器
5、String
let arr = [2,3,4,5];
console.log(arr);
for(let item of arr){
console.log(item);
}
//for of 遍历实现原理,调用了数组Array里面的Symbol.iterator 接口
function iteratorUtil(target) {
let index = 0; // 标识指针的起始位置
return { // 生成iterator遍历器对象
next: function () {
return index < target.length?{value: target[index++], done: false}:{value: target[index++], done: true}
}
}
}
let iteratorObj = iteratorUtil(arr); // 生成iterator遍历器对象
console.log(iteratorObj.next());//{value:2 , done:false }
console.log(iteratorObj.next());//{value:3 , done:false }
console.log(iteratorObj.next());//{value:4 , done:false }
console.log(iteratorObj.next());//{value:5 , done:false }
console.log(iteratorObj.next());//{value:undefeined , done:true }
Iterator接口实现底层原理,修改底层源码,拿来给自己用
function iteratorUtil( ) {
console.log('我的方法被调用了', this); // this是遍历的目标数组
// 缓存this
let that = this;
let index = 0; // 标识指针的起始位置
let keys = Object.keys(that);// 获取对象中所有key的数组
if(this instanceof Array){ // 遍历数组
return { // 生成iterator遍历器对象
next: function (){ // 可以使用缓存this解决this的指向问题,也可以使用箭头函数解决this的指向问题
return index < that.length?{value: that[index++], done: false}:{value: that[index++], done: true}
}
}
}else {// 遍历对象
return { // 生成iterator遍历器对象
next: function (){
return index < keys.length?{value: that[keys[index++]], done: false}:{value: that[keys[index++]], done: true}
}
}
}
}
Array.prototype[Symbol.iterator] = iteratorUtil;
Object.prototype[Symbol.iterator] = iteratorUtil;
let arr = [2,3,4,5];
for(let item of arr){
console.log(item);
}
// for of 消费 iterator接口
// 三点运算符消费 iterator接口
console.log(...arr);
let obj = {
username: 'kobe',
age: 43
}
for(let item of obj){
console.log(item);
}
// console.log(Object.keys(obj));输出--> (2) ["username", "age"]
十.class类详解
class类的理解
1.关键字
2.class类本质上是function
3.和函数表达式和函数声明式一样,class类也具:有类的表达式和类声明
4.类和模块的内部,默认就是严格模式,所以不需要使用 use strict 指定运行模式
类的声明:即class关键字后面跟一个类名
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
}
1.类声明不会被提升,需要先进行声明,再去访问,否则会报错,而函数声明则会提升
var person= new Person()
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
}
//报错:Person is not defined
2.不可重复声明
class Person {}
class Person {}
// 报错: Identifier 'Person' has already been declared
3.必须使用 new 调用,否则会报错,而普通构造函数不用 new 也可以执行
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
}
Person()
// 报错: Class constructor Person cannot be invoked without 'new'
类表达式:可以为匿名或命名
//匿名类
let Person = class {
constructor(name, age) {
this.name = name
this.age = age
}
}
//命名的类
let Person = class Person {
constructor(name, age) {
this.name = name
this.age = age
}
}
类的方法
1.constructor 方法:类的默认方法,通过 new 命令生成对象实例时,自动调用该方法(默认返回实例对象 this)
class Person {
constructor(name, age) {
this.name = name // 默认返回实例对象 this
this.age = age
}
toString() {
console.log(this.name + ', ' + this.age)
}
}
注意:
1.在类中声明方法的时候,方法前不加 function 关键字
2.方法间不能加分号,否则会报错
3.一个类中有且只有一个 constructor 方法
2.static静态方法:1.使用static可以给 类对象 自身添加属性,2.通过类名调用,不能通过实例对象调用,否则会报错
class Person {
static sum(x , y) {
console.log(x + y)
}
}
var p = new Person()
Person.sum(1, 2) // 3
p.sum(1,2) //报错: p.sum is not a function
3.原型方法:1.类的所有方法都定义在类的 prototype 属性上面,在类的实例上面调用方法,其实就是调用原型上的方法,2.原型方法可以通过实例对象调用,但不能通过类名调用,会报错
class Person {
constructor( ) {// 默认返回实例对象 this
}
sum( ) {
}
toString( ) {
console.log(123)
}
}
// 给 Person 的原型添加方法
Person.prototype.showName = function() {
console.log('My name is kobe')
}
// 等同于
Person.prototype = {
constructor( ) {},
sum( ) {},
toString( ) {}
}
var p = new Person()
p.toString( ) // 123
p.toval( ) // My name is kobe
Person.toString( ) //报错: Person.toStringis not a function
Person.toval( ) //报错: Person.toval is not a function
4.实例方法:通过实例对象调用,但同样不能通过类名调用,会报错
class Person {
constructor() {
this.sum = function(x, y) {
console.log(x + y)
}
}
}
var p = new Person()
p.sum(1,2) // 3
Person.sum(1,2) //报错: Person.sum is not a function
class类的继承
class Person {
// 静态资源修饰符,使用static可以给 类对象 自身添加属性
static num = 123;
// 类的构造方法
constructor(name, age){
console.log('--- constructor() ---');
this.name = name;
this.age = age;
}
// 类的一般方法
showInfo(){ // userInfo
console.log(this.name, this.age);
}
}
console.log('--------------- 实现类的继承: extends -----------------');
// 定义一个 子类
// 回顾原型继承: 子类的原型 成为 父类的实例
// 子类的构造函数.prototype = new 父类的构造函数()
class Child extends Person { // 子类的原型 成为 父类的实例
constructor(name, age, sex) {
// super做的事情: 1. 调用父类的构造方法,2. 改变父类构造方法的this指向为子类的实例
super(name, age); // super调用父类的构造方法
this.sex = sex;
}
// 父类的方法重写:当父类原型的方法不能满足子类实例需求的时候
showInfo(){
console.log(this.name, this.age, this.sex);
}
}
let child1 = new Child('xiaoming', 18, '男');
console.log(child1);
child1.showInfo();
console.log('--------------- 回顾之前的继承方式 -----------------');
function Person1(name, age) {
this.name = name;
this.age = age;
}
Person1.prototype.showInfo = function(){
console.log(this.name, this.age);
}
let person2 = new Person1('kobe', 43);
console.log(person2);
person2.showInfo();
// 子类的原型 成为 父类的实例
Child1.prototype = new Person1();
Child1.prototype.constructor = Child1;
function Child1(name, age, sex) {
// this.name = name;
// this.age = age;
Person1.call(this, name, age); // 借用构造函数继承
this.sex = sex;
}
let child2 = new Child1('xiaoming', 18, '男');
console.log(child2);
child2.showInfo();
十一:Set和Map数据结构
1.Set理解:
Set的存储结构与数组类似,Set中不允许 存放重复数据,而且没有下标,即无序不可重复的多个value的集合体
声明一个重复的数组,中有重复的数据
var arr = [111,444,333,111,222,333,444]
使用Set
var newArr = new Set(arr);//Set(4){111,444,333,222}
将结果变为数组,使用展开运算符
var arr1 = [...newArr]//(4){111,444,333,222}
let a = new Set( )
a.add(8)//Set(1){8}
let a = new Set( )
v.add(8)
v.add(6)
v.delete(8)//Set(1){6}
3.判断 Set 中是否包含某个元素–>has(value)
let a = new Set()
a.add(8)
a.add(6)
a.has(8)//true
4.clear()
let a = new Set([1,2,3,4,5])
a.clear( )
5.获取 Set 中元素个数–>size
let a = new Set( )
a.add(8)
a.add(6)
6.遍历Set
for of 形式
let a = new Set([1,2,3,3,4,5])
for(let item of a) {
console.log(item)
}//1,2,3,4,5
十二.数组的去重
ES5数组去重:indexOf
let arr = [1,2,3,4,5,1,2,3,4];
console.log(arr.indexOf(9)); // -1
function uniqArr(arr) {
let result = [];
arr.forEach(function (item, index) {
// 判断新的数组中是否包含原数组中的元素
if(result.indexOf(item) === -1){
result.push(item);
}
})
return result;
}
console.log(uniqArr(arr));
ES6数组去重: set容器
let arr = [1,2,3,4,5,1,2,3,4];
function uniqArr2(arr) {
let set = new Set(arr);
console.log(set);
let result = [];
for(let item of set){
result.push(item);
}
return result;
}
代码优化
let arr = [1,2,3,4,5,1,2,3,4];
let uniqArr2 = arr => [...new Set(arr)];
console.log(uniqArr2(arr));
十三.检查数据类型通用方法
function checkoutType(target){
return Object.prototype.toString.call(target).slice(8,-1);
}
十四.深度克隆_复制数据
- 基本数据类型存放的就是实际的数据,可直接复制
let number2 = 2;
let number1 = number2;
- 克隆数据:对象/数组
1、区别: 浅拷贝/深度拷贝
判断深拷贝还是浅拷贝:修改拷贝之后的数据会不会影响原数据,如果没有影响则是深拷贝
知识点:对象数据存放的是对象在栈内存的引用,直接复制的是对象的引用
let obj = {username: ‘kobe’}
let obj1 = obj; // obj1 复制了obj在栈内存的引用
2、常用的拷贝技术
1). arr.concat(): 数组浅拷贝
2). arr.slice(): 数组浅拷贝
3). JSON.parse(JSON.stringify(arr/obj)): 数组或对象深拷贝, 缺陷是不能处理函数数据
4). 浅拷贝包含函数数据的对象/数组
5). 深拷贝包含函数数据的对象/数组
3、手写一个深拷贝
function checkoutType(target) {
return Object.prototype.toString.call(target).slice(8, -1);
}
function clone(target) {
let result; // 最终加工拷贝完的数据
// 判断拷贝的数据是对象 || 数组 || 其他(基本数据类型,函数), 检测数据类型
let targettype = checkoutType(target);
if(targettype === 'Array'){
result = [ ];
}else if(targettype === 'Object'){
result = { };
}else {
return target;
}
// 拷贝
// arr = [1,2,3] ====> []arr2
// obj = {username: 'kobe'} ===> {}obj2
for(let item in target){
// item: 对象(key), 数组(index)
// target[item] 可以获取对应的value
let value = target[item];
// arr2[item] = arr[item]
// 判断是否是引用数据类型,因为Array或者Object里面可能还会包含Array,Object
if(checkoutType(value) === 'Object' || 'Array'){
result[item] = clone(value);
}else {
result[item] = value;
}
}
return result;
}
let obj = {username: 'kobe', age: 43, sex: ['男', '女']};
let obj2 = clone(obj);
console.log(obj, obj2);
obj.username = 'wade';
console.log(obj, obj2);
obj2.sex[0] = '混合';
console.log(obj, obj2);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。