学习总结
ES6
一、Symbol
一种新的原始数据类型Symbol,表示独一无二的值;是JS语言的第七种数据类型,是一种类似于字符串的数据类型
Symbol特点
1)Symbol的值是唯一的,用来解决命名冲突的问题
2)Symbol值不能与其他数据进行运算
3)Symbol定义的对象属性不能使用for…in 循环遍历,但可以使用Reflect.ownKeys来获取对象的所有键名
创建Symbol
//创建Symbol
let s = Symbol();
console.log(s,typeof s)//Symbol(),Symbol
let s2 = Symbol('tjc')
let s3 = Symbol('tjc')
console.log(s2 === s3)//false
//Symbol.for创建
let s4 = Symbol.for('tjc');
let s5 = Symbol.for('tjc');
console.log(s4 === s5)//true
Symbol 给对象添加属性和方法
let game = {...}
let methods = {
up:Symbol(),
down:Symbol()
}
game[methods.up] = function(){
console.log("我可以改变形状");
}
game[methods.down] = function(){
console.log("我可以快速下降");
}
console.log(game)
let youxi = {
name:"狼人杀"
[Symbol('say')]: function(){
console.log("我可以发言")
}
}
Symbol内置属性
Symbol.hasInstance
当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法
class Person{
static [Symbol.hasInstance](param){
console.log(param)
console.log("我被用来检测类型了")
return false
}
}
let o = {}
console.log(o instanceof Person)
Symbol.isConcatSpreadable
对象的Symbol.isConcatSpreadable属性等于的是一个布尔值,表示该对象用于Array.prototype.concat()时,是否可以展开
const arr = [1,2,3]
const arr2 = [4,5,6]
arr2[Symbol.isConcatSpreadable] = false
console.log(arr.concat(arr2))
二、迭代器
迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署lterator接口就可以完成遍历操作。
1)ES6 创造了一种新的遍历命令 for…of循环,lterator 接口主要供 for…of消费
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧']
//使用for...of遍历数组
for(let v of xiyou){
console.log(v)
}
for(let v in xiyou){
console.log(v)
}
//for...in循环,保存键名
//for...of循环,保存键值
2)原生具备iterator 接口的数据(可用 for of 遍历)
a)Array
b)Arguments
c)Set
d)Map
e)String
f)TypedArray
g)NodeList
3)工作原理
a)创建一个指针对象,指向当前数据结构的起始位置
b)第一次调用对象的next方法,指针自动指向数据结构的第一个成员
c)接下来不断调用 next方法,指针一直往后移动,直到指向最后一个成员
d)每调用next方法返回一个包含value和done属性的对象
const xiyou = ['唐僧','孙悟空','猪八戒','沙僧']
let iterator = xiyou[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
*注:需要自定义遍历数据的时候,要想到迭代器
const banji = {
name: "终极一班",
stus: [
'xiaoming',
'xiaoning',
'xiaotian',
'knight'
],
[Symbol.iterator]() {
//索引变量
let index = 0;
let _this = this;
return {
next: function () {
if (index < _this.stus.length) {
const result = { value: _this.stus[index], done: false };
index++;
return result;
}else{
return{value:undefined,done:true}
}
}
};
}
}
for (let v of banji) {
console.log(v);
}
三、生成器
一个特殊的函数
异步操作 (纯回调函数 node fs ajax mongodb)
函数代码的分隔符 yield
function * gen(){
console.log("hello tjc")
}
let iterator = gen();
iterator.next();
function * gen(){
console.log(111)
yield 'tjc';
console.log(222)
yield 'xth';
console.log(333)
yield 'happy birthday';
console.log(444)
}
// let iterator = gen();
// iterator.next();
// iterator.next();
// iterator.next();
// iterator.next();
for(let v of gen()){
console.log(v)
}
生成器函数参数
next方法可以传入实参
function * gen(arg){
console.log(arg)
let one = yield 'tjc';
console.log(one)
let two = yield 'xth';
console.log(two)
let three = yield 'happy birthday';
console.log(three)
}
let iterator = gen('AAA');
console.log(iterator.next());
//next方法可以传入实参
console.log(iterator.next('888'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));
*有此特性做支撑,异步编程参数传递就能够实现了
实例
异步编程 文件操作 网络操作(ajax,request) 数据库操作
1.要求:1s后控制台输出111,2s后输出222
function one(){
setTimeout(()=>{
console.log(111)
iterator.next();
},1000)
}
function two(){
setTimeout(()=>{
console.log(222)
iterator.next();
},1000)
}
function three(){
setTimeout(()=>{
console.log(333)
iterator.next();
},1000)
}
function * gen(){
yield one();
yield two();
yield three();
};
let iterator = gen();
iterator.next();
2.要求:模拟获取 用户数据 订单数据 商品数据
function getUsers(){
setTimeout(()=>{
let data = '用户数据'
//调用next方法,并且将数据传入
iterator.next(data)
},1000)
}
function getOrders(){
setTimeout(()=>{
let data = '订单数据'
iterator.next(data)
},1000)
}
function getGoods(){
setTimeout(()=>{
let data = '商品数据'
iterator.next(data)
},1000)
}
function * gen(){
let users= yield getUsers();
console.log(users)
let orders = yield getOrders();
console.log(orders)
let goods = yield getGoods();
console.log(goods)
};
let iterator = gen();
iterator.next();
四、Set(集合)
ES6 提供了新的数据结构Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator 接口,所以可以使用「扩展运算符」和「for…of…」进行遍历;Set内的数组会自动去重
集合的属性和方法:
1)size 返回集合的元素个数
2)add 增加一个新元素,返回当前集合
3)delete 删除元素,返回 boolean 值
4)has 检测集合中是否包含某个元素,返回boolean值
//声明一个Set
let s = new Set();
let s2 = new Set(['大事儿','小事儿','好事儿','坏事儿','小事儿']);
//元素个数
console.log(s2.size);
//添加新元素
s2.add('喜事儿');
//删除元素
s2.delete('坏事儿')
console.log(s2)
//检测
console.log(s2.has('好事儿'))
for(let v of s2){
console.log(v)
}
//清空
s2.clear();
console.log(s2)
集合实践
let arr = [1,2,3,4,5,,4,3,2,1]
1.数组去重
//1.数组去重
let result = [...new Set(arr)]
console.log(result)
2.交集
//2.交集
let arr2 = [4,5,6,5,6]
//复杂写法
let result = [...new Set(arr)].filter(item => {
let s2 = new Set(arr2)
if(s2.has(item)){
return true
}else{
return false
}
});
console.log(result)
//简单写法
let result = [...new Set(arr)].filter(item => new Set(arr2).has(item))
console.log(result)
3.并集
//3.并集
let union = [...new Set([...arr,...arr2])]
console.log(union)
4.差集
//4.差集
let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)))
console.log(result)
五、Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map也实现了 iterator 接口所以可以使用『扩展运算符』和『for…f…』进行遍历。
Map的属性和方法:
1)size 返回 Map 的元素个数
2)set 增加一个新元素,返回当前 Map
3)get 返回键名对象的键值
4)has 检测Map中是否包含某个元素,返回boolean 值
5)clear 清空集合,返回 undefined
//声明Map
let m = new Map();
//添加元素
m.set('name','尚硅谷')
m.set('change',function(){
console.log("我们可以改变你!!")
})
let key = {
school : 'ATGUIGU'
}
m.set(key,['北京','上海','深圳'])
//size
console.log(m.size)
//删除
m.delete('name')
//获取
console.log(m.get('change'))
console.log(m.get(key))
//遍历
for(let v of m){
console.log(v)
}
//清空
m.clear()
console.log(m)
六、class类
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,S6的class 可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
1)class声明类
2)constructor 定义构造函数初始化
constructor() 方法,这就是构造方法,而this关键字则代表实例对象
class Phone {
//构造方法,名字不能修改constructor()
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
//方法必须使用该语法,不能使用ES6的对象完整形式
call() {
console.log("我可以打电话")
}
}
//实例化对象
let onePlus = new Phone("1+",1999)
console.log(onePlus)
constructor()方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加。
3)extends 继承父类
class Phone {
//构造方法,名字不能修改constructor()
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
//父类的成员属性
call() {
console.log("我可以打电话")
}
}
class SmartPhone extends Phone {
//构造方法
constructor(brand,price,color,size){
super(brand,price)
this.color = color
this.size = size
}
photo(){
console.log("拍照")
}
playGame(){
console.log("玩游戏")
}
}
const xiaomi = new SmartPhone('小米',779,'黑色','4.7inch')
xiaomi.call();
xiaomi.photo()
xiaomi.playGame()
prototype:它是函数所独有的,它是从一个函数指向一个对象。它的含义是函数的原型对象,也就是这个函数(其实所有函数都可以作为构造函数)所创建的实例的原型对象。
prototype属性的作用:就是包含可以由特定类型的所有实例共享的属性和方法,也就是让该函数所实例化的对象们都可以找到公用的属性和方法。任何函数在创建的时候,其实会默认同时创建该函数的prototype对象。
class Point {
constructor() {
// ...
}
toString() {
// ...
}
toValue() {
// ...
}
}
// 等同于
Point.prototype = {
constructor() {},
toString() {},
toValue() {},
};
上面代码中,constructor()、toString()、toValue()这三个方法,其实都是定义在Point.prototype上面。
4)super 调用父级构造方法
5)static 定义静态方法和属性(属于类不属于实例对象)
6)父类方法可以重写
class Phone {
//构造方法,名字不能修改constructor()
constructor(brand, price) {
this.brand = brand;
this.price = price;
}
//父类的成员属性
call() {
console.log("我可以打电话")
}
}
class SmartPhone extends Phone {
//构造方法
constructor(brand,price,color,size){
super(brand,price)
this.color = color
this.size = size
}
photo(){
console.log("拍照")
}
playGame(){
console.log("玩游戏")
}
//重写部分
call(){
console.log("我可以拨打视频通话")
}
}
const xiaomi = new SmartPhone('小米',779,'黑色','4.7inch')
xiaomi.call();
xiaomi.photo()
xiaomi.playGame()
对象方法
1.Object.assign()方法可以很方便地一次向类添加多个方法。
class Point {
constructor(){
// ...
}
}
Object.assign(Point.prototype, {
toString(){},
toValue(){}
});
2.Object.is()判断两个值是否相等
3.Object.setPrototypeof()设置原型对象
七、其他
1.箭头函数
箭头函数适合与this无关的问题,定时器,数组的方法回调
箭头函数不适合与this有关的回调,事件回调,对象的方法
特性:
1.this是静态的,this始终指向函数声明时所在作用域下的this的值
2.不能作为构造实例化对象
3.不能使用 arguments 变量
(类数组对象:arguments;是一个特殊的对象,它的属性名是按照传入参数的序列来的,第1个参数的属性名是’0’,第2个参数的属性名是’1’,以此类推,并且它还有length属性,存储的是当前传入函数参数的个数,很多时候我们把这种对象叫做类数组对象)
4.箭头函数的简写
1)省略的小括号,当形参有且只有一个的时候
let add = n => {
return n + n;
}
console.log(add(9))
2)省略花括号,当代码体只有一条语句的时候,此时return必须省略,而且语句执行结果就是函数的返回值
let pow = n => n*n
console.log(pow(8))
2.ES6允许给函数参数赋值初始值
1.形参初始值,具有默认值的参数,一般位置要靠后(潜规则)
2.与解构赋值结合
function connect({host="127.0.0.1",username,password,port}){
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connet({
host: 'mq.com',
username:'root',
password:'root',
port:1005
})
3.rest参数
用于获取函数的实参,用来代替arguments
rest参数必须放在参数最后
function date(...args){
console.log(args);
}
date('檀健次','檀小呆','弹力球')
返回的为数组
4.扩展运算符[…]
能将[数组]转换为逗号分隔的参数序列
//声明一个数组
const tjc = ['檀健次','沈翊','莫青成']
//声明一个函数
function chunwan(){
console.log(arguments)
}
chunwan(tjc);
chunwan(...tjc);
5.应用
1)数组的合并
const kuaizi = ['王太利','肖央']
const fenghuang = ['曾毅','玲花']
const zuixuanxiaopingguo = [...kuaizi,...fenghuang]
console.loe(zuixuanxiaopingguo)
2)数组的克隆
const sanzhihua = ['E','G','M']
const sanyecao = [...sanzhihua]
console.log(sanyecao)
3)将伪数组转为真正的数组
const divs = document.querySelectorAll('div')
const divArr = [...divs]
console.log(divArr)
6.模块化
优点:
1)防止命名冲突
2)代码复用
3)高维护性
JS高级
一、原型与原型链
原型Prototype
默认指向一个Object空对象(即称为:原型对象)
原型对象中有一个属性constructor,他指向函数对象
给原型对象添加属性(一般都是方法),作用:函数的所有实例对象自动拥有原型中的属性(方法)
//每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)
console.log(Date.prototype,typeof Date.prototype)
function Fun(){
}
console.log(Fun.prototype)//默认指向一个Object空对象
//原型对象中有一个属性constructor,它指向函数对象
console.log(Date.prototype.constructor === Date)
console.log(Fun.prototype.constructor === Fun)
//给原型对象添加属性(一般是方法) ====> 实例对象可以访问
Fun.prototype.test = function(){
console.log('test()')
}
var fun = new Fun()
fun.test()
显示原型&隐式原型
一句话解释,函数里面有个prototype属性指向原型对象,实例化对象里面有个__proto__属性他也指向原型对象,且与构造函数的原型对象是同一个,然后原型对象里面有个constructor属性他指向的是构造函数
显示原型(prototype)
定义函数时自动添加的,默认值是一个空Object
隐式原型(proto)
创建对象时自动添加的,默认值为构造函数的prototype属性值
对象的隐式原型的值为其对应构造函数的显示原型的值
*原型链(隐式)
访问一个对象属性时,先在自身属性中查找,找到返回;如果没有,再沿着__proto__这条链向上查找,找到后返回;如果最终没找到,返回undefined
作用:查照对象的属性(方法)
构造函数/原型/实例对象的关系(图解)
构造函数/原型/实例对象的关系2(图解)
补充知识
1.函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
2.所有函数都是Function的实例(包含Function)
3.Object的原型对象是原型链的尽头
function Fn(){
this.test1 = function(){
console.log('test1')
}
}
console.log(Fn.prototype)
Fn.prototype.test2 = function(){
console.log('test2')
}
var fn = new Fn()
fn.test1()
fn.test2()
console.log(fn.toString)
// 1.函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
console.log(Fn.prototype instanceof Object) //true
console.log(Object.prototype instanceof Object) //false
console.log(Function.prototype instanceof Object) //true
//2.所有函数都是Function的实例(包含Function)
console.log(Function.__proto__ === Function.prototype) //true
// 3.Object的原型对象是原型链的尽头
console.log(Object.prototype.__proto__) //null
原型链属性问题
1.读取对象的属性值时,会自动到原型链中查找
2.设置对象的属性值时,不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
3.方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
function Fn(){
}
Fn.prototype.a = 'XXX'
var fn1 = new Fn()
console.log(fn1.a,fn1)
var fn2 = new Fn()
fn2.a = 'YYY'
console.log(fn1.a,fn2.a,fn2)
function Fn(){
}
Fn.prototype.a = 'XXX'
var fn1 = new Fn()
console.log(fn1.a,fn1)
var fn2 = new Fn()
fn2.a = 'YYY'
console.log(fn1.a,fn2.a,fn2)
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.setName = function(name){
this.name = name
}
var p1 = new Person('Tom',12)
p1.setName('Bob')
console.log(p1)
var p2 = new Person('Jack',12)
p2.setName('Cat')
console.log(p2)
console.log(p1.__proto__ === p2.__proto__)
二、instanceof
表达式:A(实例对象) instanceof B(构造函数)
如果B函数的显示原型对象在A原型链上,返回true,否则返回false
//案例1
function Foo(){
}
var f1 = new Foo()
console.log(f1 instanceof Foo) //true
console.log(f1 instanceof Object) //true
//案例2
console.log(Object instanceof Function) //true
console.log(Object instanceof Object) //true
console.log(Function instanceof Function) //true
console.log(Function instanceof Object) //true
function Foo(){
}
console.log(Object instanceof Foo) //false
(未完待续 . . . )
下周计划
复习ES6,继续学习JS高级,复习Java与高数,继续写算法题
生活碎片
河科院湖边夜景
和然然去逛街
和然然去吃饭
还是和然然去吃饭