date1107 this指向、箭头函数、解构赋值、展开运算符、Map和Set、模块化开发
今天所涉及到的知识点有点杂,也有点多,但是咱们应该平静心态,认真学习鸭。
一、this关键字
概念:每一个函数内部都有一个关键字this,this的值只和函数的调用有关,与函数书写无关。
- 特点
- 一个普通函数的全局函数,在正常调用的情况下,this指向的是window;
fun1();
function fun1(){
console.log(this);
}
运行结果:
-
如果将函数放置到对象中,通过对象的语法去获取到并调用函数,那么this指向的是对象;
fun1();
function fun1(){
console.log(this);
}
const obj = {
name:'Jack',
age:18,
sex:'男',
fun:fun1,
}
//通过对象取值的方式调用函数
obj.fun()
运行结果:
- 如果将函数作为事件处理函数,那么触发的时候,内部的this指向了事件源;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<div>我是div</div>
<script>
// 运行结果是this指向的是oDiv
// 点击div标签 打印出div的标签
fun1();
function fun1(){
console.log(this);
}
var oDiv = document.querySelector('div');
oDiv.onclick = fun1;
</script>
运行结果:
- 如果将函数作为定时器执行时的函数,那么触发的时候,内部的this指向了全部对象window。
- 注意:将函数放在定时器中,this指向的是window,定时器中这种this指向方式,和直接写window没有任何区别,一般不会使用。
// 运行结果是this指向的是window
fn();
function fn(){
console.log(this);
}
setTimeout( fn , 1000 );
setInterval(fn , 10000);
二、改变this指向
改变this指向有三种方式,分别是call,apply,bind三种方式来改变this指向,下面详细来说三种的语法和使用区别。
- call方法
- 语法形式:函数名称.call(this指向 , 参数1 , 参数2 , 参数3 , ...);
- 语法形式和bind差不多。
// this指向obj
const obj = {
a:1,
b:2,
c:3,
}
function fun(x , y){
console.log(this , x , y);
}
fun.call(obj , 300 , 400);
- apply方法
- 语法形式:通过apply(this指向 , 参数1 , 参数2 , 参数3 , ...)修改this指向。
- 参数需要用方括号给括起来。
// 运行结果:obj
const obj = {
a:1,
b:2,
c:3,
}
function fun(x , y){
console.log(this , x , y);
}
fun.apply(obj , [300 , 400 , 500]);
- bind方法
- 语法形式:通过bind(this指向 , 参数1 , 参数2 , 参数3 , ...)修改this指向。
- 必须赋值给一个变量返回,返回的是一个新函数。
//运行结果:obj
const obj = {
a:1,
b:2,
c:3,
}
function fun(x , y){
console.log(this , x , y);
}
const newFn = fun.bind(obj , [300 , 400 , 500]);
console.log(newFn);
三、ES6
ES6其实就是JS发展过程中的某一个版本而已 那个版本的版本号叫做ES6
##微信
- 在最初的时候 是不具有微信支付的
- 随着版本的更新 在某一个版本推出了微信支付
##JS
- 在最初的时候 是只有var 关键词可以声明变量
- 随着版本的更新 在某一个版本推出了新的变量声明方式
##JS的更新
- 在推出ES6的时候 这个版本推出的东西比较多
- 所以后续程序员为了方便记忆 把ES6以后的版本 统称为ES6+
四、let与const
ES6 新增两种变量声明的方式:let和const。 之前我们学的ES5我们只能使用var声明变量,语法 和 var 一样
let 变量名 = 值;const 变量名 = 值
let/const 与var 的差异 1.let/const 声明的变量 不允许出现重复的变量,
使用var 声明变量的时候可以出现重复声明 后赋予的值会覆盖前面的值,let/const 不允许变量重复声明;
2.let/const 声明的变量没有变量提升
也就是不可以提前调用,var声明的变量可以提前调用,打印出的是undefined。
3.let/const声明的变量会受限于所有的{} ,
var关键字声明的局部变量 可以在外部使用 正常打印出值,也就是使用let/const声明的变量是块级作用域 在函数内定义的局部变量不可以在函数外部使用 如果在函数外部使用会报错。
let/const的差异:
1.let声明的叫做变量(后续可以修改内部的值), 2.const声明的变量叫做常量(后就不能修改内部的值)
// 是否可以提前调用
// var打印undefined let/const报错
console.log(a);
console.log(b);
var a = 1 ;
var b = 2 ;
let a = 1 ;
let b = 2 ;
// 局部变量是否可以在函数外部使用
function fun(){
var a = 1 ;
var b = 2 ;
}
fun();
// 是否可以重复定义变量
// var可以重复定义变量 let/const不可以重复定义变量
var a = 11 ;
var a = 22 ;
let b = 11 ;
let b = 22 ;
console.log(a);
console.log(b);
五、随堂练习
第一种情况:面试题: 对象obj打印的是什么。
// 打印出:{name: 'Jacks'}
const obj = { name:'Jack' };
obj.name = 'Jacks';
console.log(obj);
第二种情况:面试题: 对象obj打印的是什么。
// 第二种情况:
// 打印结果:直接报错
// const声明的值重新修改的是其中的内存地址 但是const的内存地址不可以被改变
const obj = { name:'Jack' };
obj = { name:'Jacks' };
console.log(obj);
第三种情况:面试题: 对象obj打印的是什么。
// 第三种情况:
// 打印结果:{name: 'Jacks'}
// var声明的变量后面声明的值会覆盖前面声明的值
var obj = { name:'Jack' };
obj.name = 'Jacks';
console.log(obj);
第四种情况:面试题: 对象obj打印的是什么。
// 面试题二
// 第一种情况:
// 打印结果:1s过后5次循环的值为5
// 前面的几次循环的值都被最终的值给覆盖了 最后var被赋予的值为第五次循环的5
// var声明的i是一个全局变量
for(var i = 0 ; i < 5 ; i++){
setTimeout(function(){
console.log(i);
} , 1000)
}
第五种情况:面试题: 对象obj打印的是什么。
// 第二种情况:
// 打印结果:1s过后0 1 2 3 4
// let声明的值不可以给覆盖 并且在循环5次过后 打印出的值就是5次循环的值
// let声明的i是一个块级作用域
for(let i = 0 ; i < 5 ; i++){
setTimeout(function(){
console.log(i);
} , 1000)
}
六、箭头函数
- 概念:箭头函数就是对ES5普通函数写法上的一个优化。
- 语法形式:普通写法:(书写形参) => (书写函数调用时执行的代码)
- 箭头函数优化:箭头函数如果只有一个形参的时候 可以不写前面小括号
下面就是各种箭头函数的源代码,每一种都很重要,要认真看哦,运行结果可以自己复制代码到编译器运行。
// 普通函数
const fun1 = function fun1() {
console.log(111);
}
fun1();
// 箭头函数
// 将普通函数转化为箭头函数
const fun2 = () => {
console.log(222);
}
fun2();
// 箭头函数的优化
// 函数体只有一行代码的时候可以不写{}
const fun3 = () => console.log(333);
fun3();
// 只有一个形参时 可以不写前面的小括号
const fun4 = a => console.log(444);
fun4();
// 计算累加和
const fun5 = function(a , b){
console.log(a+b);
}
fun5(100 , 200);
const fun6 = (a, b) => a + b;
console.log(fun6(100, 200));
七、解构赋值
- 概念:是ES6新增的获取数组和对象中的每一项值的方法,快速从数组或对象中取出成员的一种语法。
- 两种:数组的结构赋值和对象的解构赋值。
// 数组的解构赋值
const arr = [100 , 200 , 300 , 400];
// 通过ES5的方式获取每一项值
let num1 = arr[0];
let num2 = arr[1];
let num3 = arr[2];
let num4 = arr[3];
console.log(num1 , num2 , num3 , num4);
// 通过ES6的方式获取数组的每一项值(解构赋值)
let[num11 , num22 , num33 , num44] = arr;
console.log(num11 , num22 , num33 , num44);
// 对象的解构赋值
// 通过ES5的方式获取每一项值
const obj = {
a: 10,
b: 20,
c: 30,
}
console.log(obj.a , obj.b , obj.c);
// 通过ES6的方式获取每一项值
let{a , b , c} = obj;
console.log(a , b , c);
console.log(a , b , c);
八、箭头函数与普通函数的区别
- 箭头函数内部没有this 所以他的this取决于书写的时候
- 箭头函数内部没有arguments对象,使用的时候尽量不用使用,只有普通函数可以使用 箭头函数内部没有arguments会报错
// 普通函数的this指向window
function fun1() {console.log(this);}
fun1();
// 箭头函数
// 函数的上一级是window 所以this指向window
const fun2 = () => {console.log(this);}
fun2();
// 普通函数的this指向obj
const obj = {
name:'Jack',
sex:'男',
age:18,
city:fun1,
}
obj.city();
// 箭头函数美没有this指向
const obj2 = {
name:'Jack',
sex:'男',
age:18,
city:fun2,
}
obj.city();
九、展开运算符
- 语法形式:...数组(对象);
- 作用:展开数组或者对象,相当于把数组两次包裹的中括号去掉。
// 对象的展开运算符
const obj = {
a:10,
b:20,
c:30,
}
// 使用key键名来获取值
console.log(obj.a , obj.b , obj.c);
// 不支持这样的写法
// console.log(...obj);
// 可以这样写
const obj1 = {
...obj,
d:40,
f:50,
}
console.log(obj1);
// 数组的展开运算符
const arr = [100 , 200 , 300 , 400 , 500];
const arr1 = [...arr , 600 , 700];
console.log(...arr);
console.log(...arr1);
// 函数的展开运算符
function fun1(a , b , c , d , e){
console.log(a , b , c , d , e);
}
fun1(...arr);
十、Map和Set
map和set数据结构
1.set方法
-
概念:ES6新推出的两种数据结构,set类似与数组的一种数据结构,内部按照索引排序(但是不能通过索引取值)。
-
语法形式:var 变量 = new set([参数1 , 参数2 , 参数3 , ...]);
-
特点:
- 天生不支持重复数据 所以可以利用set来数组去重。
- set中的size类似于数组中的length。
-
set的增删查改
- 新增数据:set数据结构.add(数值);
- 查询数据:set数据结构.has(数据); 返回布尔值 找到返回true 找不到返回false
- 删除数据:set数据结构.delete(数据);
- 清空数据:set数据结构.clear();
-
循环遍历set数据结构
- 语法形式:set数据结构.forEach(item , key , origin){}
// 设定一个set
const s = new Set([100 , 200 , 300 , 400 , 500 , 600]);
console.log(s);
// set的长度
console.log(s.size);
// 打印出其中的值 这样打印输出的是undefined
// console.log(s[0]);
// console.log(s[1]);
// console.log(s[2]);
// console.log(s[3]);
// console.log(s[4]);
// console.log(s[5]);
// 判断set中是否有这个数据
console.log(s.has(100));
console.log(s.has(10000));
// 向set中新增数据
// 一次只能新增一个
// s.add(1000);
// s.add(1000 , 20000);
console.log(s);
// 向set中删除数据
s.delete(1000);
console.log(s);
// set数据清空
// s.clear();
// console.log(s);
// 循环遍历set
// set中没有键名key 所以key打印出来和item数值一样
s.forEach(function(item , key , origin){
console.log(item , key , origin);
})
// 利用set对数组去重
const arr = [1 , 2 , 1 , 2 , 3 , 6 , 2 , 6 , 4 , 8 , 10 , 5];
console.log([...new Set(arr)]);
2.map方法
-
概念:ES6推出的一种数据结构,和set一样,也不支持重复数据,类似于对象的一种数据结构,但是map的key可以是任意类型的值。
-
语法形式:var m = new Map([[key , value] , [key , value] , ...]);
- 输出形式是以箭头函数的形式输出,eg:key => value;
-
在实际开发中 我们使用map 的场景想要将对象的key用于字符串之外的数据形式;
-
map数据结构的增删查改
- 新增数据:map数据结构.set(key , item); 向当前数据结构中新增数据
- 获取数据:map数据结构.get(key); 获取指定的key对应的value
- 查询数据:map数据结构.has(key); 查询数据结构中是否存在当前key 返回布尔值 有就返回true 无就返回false
- 删除数据:map数据结构.delete(key); 删除当前数据结构对应的key
- 清空数据:map数据结构.clear(); 清空当前数据结构
-
循环遍历map数据结构:
- 语法形式:map数据结构.forEach(item , key , origin){}
// map语法
// 普通对象获取数值
const obj = {
a:10,
b:20,
c:30,
}
console.log(obj);
console.log(obj.a);
console.log(obj['a']);
// map数据结构创建单个
const m = new Map([['a' , 100] , ['b' , 200]]);
console.log(m);
// map数据结构创建多个
const arr1 = [1 , 2 , 3];
const arr2 = [4 , 5 , 6];
const m1 = new Map([[['c' , 300]] , [arr1 , arr2] , ['arr1' , [11 , 21 , 31]] , ['arr2' , [22 , 23 , 24]]]);
console.log(m1);
// set增加map数据数值
m.set('name' , ['q' , 'w' , 'e' , 'r']);
console.log(m);
// get获取map数据数值
console.log(m.get('name'));
// has查看map中是否有 返回布尔值
console.log(m.has(100));
console.log(m.has('a'));
// delete删除map数值
m.delete('a');
console.log(m);
// clear清空map数值
console.log(m1);
m1.clear();
console.log(m1);
console.log('');
// 循环遍历map
console.log(m);
m.forEach(function(item , key , origin){
console.log(item , key , origin);
})
十一、对象语法的简写
这一块没有什么理论的知识,所以直接上了代码。
/*
对象语法的简写
*/
// 对象的简写
const obj = {
name: name,
sex:'男',
age:18,
}
console.log(obj);
const obj1 = {
name,
sex:'男',
age:18,
}
console.log(obj1);
// 向对象中添加函数
const obj3 = {
name:'Jack',
sex:'男',
age:18,
fun1:function fun1(){
console.log(111);
}
}
console.log(obj3);
const obj4 = {
name:'Jack',
sex:'男',
age:18,
fun1:function fun1(){
console.log(111);
},
fun2(){
console.log(222);
},
}
console.log(obj4);
十二、模块化开发
概念:就是将功能拆分开 每一个功能写道一个JS文件中 (整理出来 积木 一个个的模块)
后续根据实际需求 将不同的JS文件拼接到一起 (按照图纸 将每一个积木拼接一个完整的小汽车或者小房子)
主要是把一些核心的功能拆分出来封装成一个模块 不要分得太细 分得太细维护和操作的时候会很麻烦
将多个逻辑分别写到多个JS文件中 每一个文件都只能使用当前文件内的变量 每一个文件 就是一个独立的作用域(文件作用域)
-
ES6使用模块化开发的前提:
- 页面必须使用服务器 以服务器的形式打开
- script标签行内必须配置type="module" eg:
-
如果想要拼接的话 需要导入别的文件到自己的文件内
-
前提:导入的文件 必须有导出的内容
-
导出:向外部暴露一些内容 可以是变量 可以是函数
-
导入:引入别的文件向外部暴露出的那些内容