es 学习笔记
1 let
let是var的升级版,更符合java和c的版本,以下为var与let的区别
- 不能重复声明一个变量,而var可以。
- 拥有块级作用域。就是花括号里的变量,外面不能用
- 不存在变量提升
- 有一个常见的var的bug,就是for(var i = 0; i< 3;i++){s[i].click} 这个时候只会执行s[3],因为i变成了全局的,i就是3。这就是块级作用域的问题
2 const 定义常量
const PS = “15”
- 必须初始化
- 常量无法修改
- 一般要大写
- 块级作用域
- 数组和对象可以修改,比如
SS[5] = "541" obj.name = "44";
这个有点像c语言里的#define
3 解构赋值
3.1 数组
const score = [90, 100, 95];
let [math, English, Chinese] = score;
这个不是很常用
3.2 对象
const student = {
name: "",
score: 100,
gotoschool: function(){
console.lof("sfji");
}
}
let {gotoschool} = student;
//或者let {name, score, gotoschool} = student;
gotoschool();
let arr = ["s", "a", "b"];let {x1, x2, x3} = arr;
x123分别为s、a、b可以进行这样的赋值操作,包括对象(相当于结构体)
4 对象的简化写法
能够使用外部已经赋值的变量
能够简化对象里的函数定义,不需要再写function
let name = "xiaoming";
let score = 100;
let gotochool = function(){};
const student{
name,
score,
gotoschool,
eat(){}
}
5 ``反单引号模板字符串
和双引号一样是一种定义字符串的方式
- 直接可以换行
- 可以直接字符串拼接 例如:
${X}是我喜欢的东西
就是将x与汉字连接
6 => 箭头函数
this
是静态的,始终指向声明时的作用域,无法改变。- 不能用
argument
变量。 - 形参只有一个的时候可以省略括号
- 只有一条语句时可以省略花括号
- 这条语句是
return
时,可以省略return
;如let a = n => n*n
;
let getname = () => {}
当我们在使用setTimeout这种直接调用的函数的时候,函数没有和其他的东西绑定,所以里面的this就是默认的windows,这就是箭头函数的好处setTimeout(() => {}, 2000);
7 形参赋初始值
function ss(df,dfd = 5){}
ss(5);
//55
赋初始值的要靠后,假如没有传参就会使用初始值
8 …X rest参数
可以用来替代argument,不同的是需要在函数声明的时候形参写成…X的形式,如
function fn(a, b, ...args){} fn(1,2,3,4,5);
//args[0] = 3,args就是一个数组
rest参数要放在最后
9 …扩展运算符
9.1 描述
需要将一个数组的所有元素单独作为参数传进去的时候使用
例如
const tfboys = ['yyqx', 'wy', 'wjk'];
function chunwan(){
console.log(argument);//获取实参信息
}
chunwan(...tfboys)//这里是三个实参传进去了,而不只是一个数组
9.2 一些应用
9.2.1 数组及对象的合并
const arr1 = ["A", "B", "C"];
const arr2 = ["D", "E"];
const zuhe = [...arr1, ...arr2];
9.2.2 数组及对象的克隆
const arr3 = [...arr1];
可以直接将数组克隆而不用使用函数,相对来说更为简洁
9.2.3 将伪数组转为真正的数组
const divs = document.querrySelectorAll("div");
const divarr = [...divs];
//这里就是将divs这个对象转为数组,可以使用数组的方法
10 Symbol()数据类型
10.1 Symbol 特点
- symbol本质是一个唯一随机的字符串,而且我们是无法打印出来的
- 括号里是相当于注释的描述性文字,如Symbol(“注释”);
- 无法运算和比较
- Symbol.for(“key”),这种方法的symbol可以相等
这一部分暂时不学了,有点难理解,又感觉用到的场景不是很多
10.2 Symbol内置属性
对象调用属性有两种方法,而symbol内置属性定义的函数只能用[]的方式来调用这个属性,用点.不行
symbol的内置属性是Symbol的一些方法,然后用在一些对象或者构造函数或者类里面,充当一些函数名,在特定的场景下面这个自己定义的,函数名为symbol内置属性的函数会被调用
11 迭代器
11.1 介绍
自带iterator接口的数据
Array StringSset Map Argument TypedArray Nodelist
iterator就是一个array自带的Symbol内置属性,当使用for in或者for of的时候就会调用。
11.2 for of 与 for in
const xiyou = ["孙悟空", "唐僧", "猪八戒", "沙和尚"];
for(let i of xiyou){//键值
console.log(i);//孙悟空 唐僧 猪八戒 沙和尚
}
for(let i in xiyou){//键名
console.log(i);//1234
}
11.3 自定义迭代器接口
const banji = {
name:"终极一班",
stus:[
"xiaoming",
"xiaotian"
]
}
for(let i of banji){
console.log(i);//报错,会显示banji不是一个能够迭代的对象
}
for(let i in banji){
console.log(i);//输出的时name stus
}
for(let i of banji.stus){
console.log(i);//xiaoming xiaotian
}
此时需要的是实现第三个的功能,但是不采用这种方式,而是使用自定义迭代器的方式
name:"终极一班",
stus:[
"xiaoming",
"xiaotian"
],
[Symbol.iterator](){//返回的是一个next函数,
let index = 0;
let _this = this;
return{
next: ()=>{
if(index < _this.stus.length){
const result = {
value: _this.stus[index],
done: false
}
index++;
return result;
}
else{
return {
value: undefined,
done: true
}
}
}
}
}
}
for(let i of banji ){
console.log(i);
}
上面代码最主要的部分就是那个Symbol.iterator{}这就是当使用for in和for of的时候会触发的函数,我们需要返回一个对象,这个对象需要包含next函数,next函数需要返回一个对象,这个对象需要包含value,done。
next一开始会指向第一个元素,返回value的值在i里面,当done变成true的时候会停止,这个的value值不会被返回,所以就是这样实现了一个自定义的迭代器。
12 生成器函数 yield
12.1 介绍
解决回调地狱的,就是函数套娃,不停回调
语法中,遇到yield就停,遇到next继续
fuction* 和普通的function 有点不一样
例子
function fun1(){}
function fun2(){}
function * getdata(){//声明方式不同
console.log("start");
yield fun1;//多了一个关键字yield
yield fun2;
}
let iterator = getdata();//也可以直接调用getdata();
itetator.next();//这个next就是调用第一个yield和fun1, 再使用iterator.next()就会调用第二个
传参问题:
使用next()传参
next就是生成器版本的return
12.2 实例
function getUsers(){
setTimeout(() =>{
let data = "用户数据";
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();//这里将gen实例化,好像是必须实例化,才能在第一个函数中使用next
iterator.next();
13 Set集合
这是一个新的数据结构,内有iterator接口,所以能够使用for in和for of,当然for in是不会和数组一样有123的,声明都没有,而for of能够输出集合里的所有的元素。
会自动将重复的元素去除,就算是在声明的时候添加了多个相同的元素,它就只会保存一个
13.1 声明
let set1 = new Set();//与数组不同,必须使用new
let set2 = new Set(["1", "2"]);
13.2 部分集合的方法
- console.log(set.size);//返回集合大小
- set.add(“fsf”);//增加一个集合元素,返回集合
- set.delete(“sffs”);//返回boolean值,是否删除成功,有的时候可能都没有这个元素
- set.has(“sf”);//判断是否有这个元素,返回boolean值
14 promise
这个暂时不学
15 Map地图对象
15.1 介绍
map其实就是一个升级了的对象, 能够通过键名访问键值,与对象的区别就在于这个键名可以是对象,不只是局限于字符串
15.2 部分函数
声明
就是普通的对象声明方式
let m = new Map();
添加元素
m.set("name", "iceylia");
m.set("change", function(){});
得到大小
console.log(m.size);//2
清空地图
m.clear();
访问元素
console.log(m.get("name"));//iceylia
console.log(m.has("name"));//true;
遍历
for(let v of m){
console.log(v);
console.log(v[1]);//iceylia function
}
16 class类
16.1 介绍
类的定义在很多的语言里面都有,其实类的许多功能也能够用之前的语法实现,只是为了让js更加像是面向对象的编程。
class phone{
constructor(brand, price){//这个函数就是在类被声明的时候会自动执行这个函数。
this.brand = brand;
this.price = price;
}
call(){
console.log("我可以打电话");
}
}
let oneplus = new phone("1+", 3000);
oneplus.call();//我可以打电话
console.log(oneplus.brand);//1+
16.2 静态成员
在原本的构造函数里面也有静态对象
function phone(){
this.brand = brand;
this.price = price;
}
phone.call = function(){
console.log("wfw");
}//这个时候这个call是构造函数的对象
phone.prototype.call2 = funciton(){}//这个函数实例化对象就能使用,prototype就是原型的意思,可以理解成构造对象。
let oneplus = new phone("1+", 3000);
oneplus.call();//undefined;
而我们在类里面也可以定义静态成员,就是在成员名前面加上static
class phone{
constructor(brand, price){
this.brand = brand;
this.price = price;
}
static call(){
console.log("我可以打电话");
}
}
16.3 构造函数的继承
function phone(brand, price){
this.brand = brand;
this.price = price;
}
function smartphone(brand, price, color, size){
phone.call(this, brand, price);//这个是不能更改名字的
//大概意思就是将这个构造函数的对象和与父类相同的属性传过去
this.color = color;
this.size = size;
}
smartphone.prototype = new phone;//这里也就是将smartphone的父类原型指定为phone
const chuizi = new smartphone("锤子", 2999, "黑色", "5inch");
console.log(chuizi.brand);//锤子
console.log(chuizi.call);//undefined;
16.4 类的继承
class phone{
constructot(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;//定义子类的成员属性
}
}
const xiaomi = new smartphone("小米", 2999, "black", "5.5inch");
xiaomi.call();//我可以打电话;
如上例子,我们可以调用父类的方法,但是当我们子类也有一个同名的方法的时候,就无法通过子类调用这个父类的同名方法,只能使用子类里面的方法.
16.5 get set
16.5.1 get
get其实就是一个特殊的class的函数的修饰词,看起来是函数,实际上是一个class里的变量或者说是属性
class phone{
get call(){
console.log("call1");
return 5;
}
}
const oneplus = new phone();
console.log(oneplus.call);//call1 5;
作用就是能够动态地改变这个变量的值,每使用一次set参数,就会调用一次set函数,将函数返回值编程set参数的值
16.5.2 set
set形式上与get相似,一般就是利用里面的函数判断是否能够实现这个赋值,如果你给变量赋值不合法,或者不符合规则,那么就可通过函数直接赋值失败
class phone{
set call(newvalue){//必须有一个参数
console.log("call1");
}
}
const oneplus = new phone();
oneplus.call = "454";
17 数值扩展
17.1 Number.EPSILON 最小精度
epsilon英文中是希腊中第五个字母,小的正数的意思,再js里面就是js的最小精度。
用途,在我们进行浮点数的运算的时候,我们都知道,浮点数其实是有许多没有显示出来的位数的,一直到最小的精度,所以会出现下面的问题
console.log(2.1 - 1.1 === 1.0);//false;
//用EPLISON解决
if(Math.abs(2.1-1.1) < Number.EPLISON){
console.log(1);
}
else{
console.log(0);
}
17.2 变量的进制表达方式
形式都是0+字母加 数字
//二进制
let b = 0d101;//5;
//八进制
let o = 0o777;
//十六进制
let x = 0xfff;
17.3 Number.isNaN()判断是否为一个数字
在es6之前这个isNaN()就是一个单独的方法,所以我们现在也可以直接使用之前的那种形式
console.log(isNaN(13));
17.4 Number.parseInt()将字符转为整形的数字
同上,之前就是一个单独的函数
console.log(Number.parseInt("123"));//ture;
let a = Number.parseInt("123");//true;
17.5 Number.isInteger() 是否为整形
略
18 对象方法扩展
18.1 Object.is() 判断两个值是否相等
与===
相似
有一点不同,就是全等的时候NaN ===NaN
是false,而is是true
Object.is(120, 120);//true;
console.log(NaN === NaN);//false;
18.2 Object.assign() 对象的合并
assign()将后面的对象覆盖到前面去,假如有冲突,那么就保留后面的对象。
const test1 = {
name: "1",
tel:"154"
}
const test2 = {
name: "2",
}
console.log(Object.assign(test1. test2))//2 154;
18.3 Obeject.defineProperty() 对象添加属性
let object1 = {
name: iceylia
}
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
返回值是该对象,第一个参数是对应的对象,第二个是对象的属性名,第三个参数是配置对象,配置对象里面最重要的是value的属性,也就是属性的值,
enumerable 属性是否可被枚举到,默认是false,我们想要通过for in 获取到,就需要设置这个参数为true
writable 属性是否可被修改,一开始也为false
configurable 属性是否可被删除, 默认false
get 参数是一个函数,在属性被访问的时候会调用这个函数,必须有返回值,作用就是将这个属性和一个变量动态的绑定在一起,每次读取这个属性的时候,都会调用这个参数来看看那一个变量是什么,一般叫这个函数为getter
set 参数与get差不多,当你在改变属性的值的时候,就会调用这个函数,然后就会修改对应的变量的值
let number = 18;
let x = {
name: "iceylia",
}
Object.defineProperty(x, "age", {
get: function() {
return number;
},
set: function(value) {
number = value;
}
})
19 模块化
19.1 介绍
模块化就是将别处代码的变量能够在这里使用,而模块化的好处就是高维护,避免命名冲突,代码复用。
在使用模块化导入的时候,需要将export的type设置成module(模块)
<script type="module">
import * as test1 from "./test.js";
test1.test();
console.log(test1.name);
</script>
此时同级下有个叫test1.js的文件
export let name = "iceylia";
export function test(){
console.log("test success");
}
//结果就是test success 和iceylia
19.2 export暴露方法
- 分别暴露,就是将每个要暴露的对象和变量前面都加上export,如介绍中所写的那样。
- 统一暴露,在要暴露的文件最后面export{name, test},用这种格式将所有要暴露的对象写里面
let name = "iceylia";
function test(){
console.log("test success");
}
export{name, test};
- 默认暴露,像是对象的写法,使用的时候要先用default然后才能用里面的变量
export default{
name: "iceylia",
test: function(){
console.log("test success");
}
}
<script type="module">
import * as test1 from "./test.js";
test1.default.test();
console.log(test1.default.name);
</script>
19.3 import导入方式
- 通用方式,如介绍所写,
import * as X from " "
X就是自己定义的名字,*是文件里要引入的东西 - 解构赋值方式
import {name, test} from "./test1.js";//名字不冲突,直接用文件里的名字
import {name as name2, sss} from "./test2.js";//名字冲突,需要用as起别名,就起了一个name2
import {default as x} from "./test3.js";//默认暴露可用,此时用x.name与x.test访问文件内容
console.log(name);//iceylia
- 简便形式,这种方式只能对于默认暴露形式生效
import X from "./test.js";
console.log(X.name);
20 es7
20.1 includes()
判断数组里面,是否包含某个元素
const test = [1, 5, 8];
console.log(test.includes(5));//true;
20.2 ** 幂运算
2 ** 5 相当于 Math.pow(2, 5),都是二的五次方;
20.3 reduce()
将数据进行条件统计,与filter过滤不是一个概念,reduce是为了统计数组中有多少个符合条件的数据。
const arr = ["1", "ff", "55"];
let initValue = 0;
const result = arr.reduce((preValue, currElem)=>{
return preValue + 1;
},initValue);
result一般使用两个参数,第一个是一个函数,第二个是初始值。第三个参数是currElem的index,第四个参数是arr本身
reduce执行一次,currElem就会后移一位,遍历完了reduce就结束了
preValue函数上一次指向的返回值,一开始的时候preValue是initValue,如果没写initValue,那就是arr[0],这样会使reduce少执行一次
案例中的方法,preValue初始值为0,curr为1,执行一次,preValue为1,curr为ff,再执行一次,pre为2,curr为55,最后执行一次的返回值就是reduce的返回值了,所以result为3,就是数组的长度。
reduce如何条件统计的呢
const result = arr.reduce((preValue, currElem)=>{
return preValue + (currElem.length === 2 ? 1 : 0);
},initValue);
这样的result就是数组中长度为2有多少了