改变this指向
- this的指向:
- this 的指向只跟函数的调用有关, 跟函数的书写没关系
- 手动更改函数内部 this 指向的方法
- call
- 语法: 函数.call(将函数内的this指向什么, 传递给函数的参数1, 传递给函数的参数2...)
- 将方法附加在函数后调用, 可以忽略函数本身的this, 并且修改为你传递进去的第一个参数
- apply
- 语法: 函数.apply(将函数内的this指向什么, [传递给函数的参数1, 传递给函数的参数2...])
- 该方法和第一个方法类似, 也是附加在函数后调用, 可以忽略桉树本身的this, 并且修改为你传递进去的第一个参数
- bind
- 该方法和前两个类似, 也是附加在函数后调用, 可以忽略函数本身的this, 并且修改为你传递进去的第一个参数
- 但是和 call/apply 有一点完全不同, 就是 bind 使用之后, 不会立即调用原本的函数会返回一个功能与原本函数相同但是修改了 this 指向的函数
var obj = {
name: 'QF001',
age: 18,
}
function fn(a, b) {
console.log(this, a, b);
}
fn()
//window undefined undefined
fn(100,200)
window 100 200
- 函数.call(修改this的指向)
fn.call(obj, 10, 20)
//{name: 'QF001', age: 18} 10 20
- 函数.apply(修改this的指向,[传递给函数的参数1,传递给函数的参数1])
fn.apply(obj, [10, 20])
//{name: 'QF001', age: 18} 10 20
- 函数.bind(修改this的指向)
fn.bind(obj);
// 不会立即调用
var res = fn.bind(obj)
console.log(res);
/* fn(a, b) {
console.log(this, a, b);
} */
// 打印出一个新的函数,不过内容思原来的
res(100,200)
// {name: 'QF001', age: 18} 100 200
ES5 和 ES6
-
ES5 和ES6 是 ECMAscript的某个版本
-
let / const 与 var 的区别
- var 会进行预解析
- let 与const 不会进行预解析
- var 会进行预解析
// 1.预解析(变量提升)
console.log(a)
undefined
var a = 100;
console.log(a); // 100
在定义之前使用这个变量 不报错, 返回 undefined
console.log(b);
// Uncaught ReferenceError: Cannot access 'b' before initialization
// 报错 不能再定义之前使用这个变量(暂时性死区)
let b = 200;
console.log(b);
console.log(num);
// // Uncaught ReferenceError: Cannot access 'b' before initialization
// // 报错 不能再定义之前使用这个变量(暂时性死区)
const num = 100;
console.log(num);// 100
2. var 可以声明两个重名的变量
* let 与const 不能定义重名变量
// 2. 重复变量名
var n1 = 100;
var n1 = 200;
console.log(n1);//200
let n2 = 100;
let n2 = 200;
Uncaught SyntaxError: Identifier 'n2' has already been declared
const n2 = 100;
const n2 = 200;
// Uncaught SyntaxError: Identifier 'n2' has already been declared
// 报错
3. var没有块级作用域
* let 与const 有块级作用域
// 3.块级作用域
// 定义: 任何一个代码段的{}都会限制该变量的使用范围
if (true) {
var num = 200;
console.log(num);//200
}
console.log(num);//200
var 定义的变量只有函数决定作用域
在自己作用域里面找,有则打印,没有则打印undefined
if (true) {
let num1 = 200;
console.log(num1);//200
// let 定义的变量 只能在if 的 {} 内使用
}
console.log(num1);
Uncaught ReferenceError: num1 is not defined
if (true){
const num2 =300;
console.log(num2);//300
// const 定义的变量 只能在if 的 {} 内使用
}
console.log(num2);
// Uncaught ReferenceError: num1 is not defined
// 报错
- let 与const 的区别
- let 可以定义变量的时候 不进行赋值
// 1. let 可以定义变量的时候 不进行赋值
let num;
console.log(num); //undefined
num = 100;
console.log(num);//100
- const 在定义的时候必须赋值
const num;
// const 声明时 必须赋值
Uncaught SyntaxError: Missing initializer in const declaration
// const 在定义的时候必须赋值 因为const 定义时是常量
console.log(num); //undefined
num = 100;
console.log(num);//100
- let 定义的变量可以修改
let num = 400;
console.log(num); //400
num = 200;
console.log(num); //200
- const 定义的常量一经赋值不能再修改
// const num = 400;
// console.log(num); //400
// num = 200;
// console.log(num);
// ES5和ES6.html:131 Uncaught TypeError: Assignment to constant variable.
// 报错
// const 定义的变量不能修改
// 实例
const obj = {
name: '张三',
age: 18,
};
// obj.name = 'test'
obj = {}
console.log(obj);
// 报错
箭头函数
- 在ES6 中对 “函数表达式”的一种简写
- 函数表达式 又叫做 匿名函数
- 不需要单独定义的函数
- 直接使用的位置
- 在之前的函数里面 省略掉function 在() 和{}之间一个箭头
const fn = () => { }
setInterval(() => { })
setTimeout(() => { })
xxx.forEach(() => { });
// 实例
const fn1 = function () {
console.log('我是fn1的函数');
//我是fn1的函数
}
fn1();
const fn2 = () => {
console.log('我是fn2的箭头函数');
//我是fn2的箭头函数
}
fn2();
- 箭头函数的特殊时刻
- 箭头函数某些时候可以省略()
- 当形参只有一个的时候 可以不写 ()
注意: 必须只有一个形参的时候可以省略, 没有形参或者有多个形参, 必须写小括号
- 当形参只有一个的时候 可以不写 ()
// 1.箭头函数某些时候可以省略()
const fn3 = =>{
// 报错
// Uncaught SyntaxError: Unexpected token '=>'
console.log('我没有参数');
// 我没有参数
}
fn3();
const fn4 = a => {
console.log('我有一个形参:' + a);
//我有一个形参:100
}
fn4(100);
const fn5 = a, b => {
// 报错
// Uncaught SyntaxError: Unexpected token '=>'
console.log('我有两个形参:', a, b);
}
fn5(100, 200);
- 箭头函数某写时候可以省略{}
- 当你的代码只有一行的时候,可以不写{}并且自带return
- 并且会自动把这一句话的结果当作函数的返回值
// 2.箭头函数某写时候可以省略{}
const fn1 = (a,b)=> a + b ;
// 2.1 如果箭头函数需要执行的代码只有一行, 可以省略 大括号, 并且自带 return
console.log(fn1(100,200));//300
- 箭头函数没有arguments
// 3.箭头函数没有arguments
// const getfn = function (){
// console.log(arguments);
// }
// getfn(100,200,300);
//[100,200,300,...]
// const getfn1 = function () {
// console.log(arguments);
// }
// getfn1(100,200,300);
//得到一个数组 并且有100,200 300
// 能够拿到所有的传递进来的实参, 但是这种写法了解即可, 不推荐
// const fn2 = ()=>{
// console.log(arguments);
//报错 当前函数是箭头函数, 所以不能使用
// //Uncaught ReferenceError: arguments is not defined
// }
// fn2(100,200,300);
- 箭头函数内没有 this
- 箭头函数内的this,就是外部作用域的this
- 即:箭头函数没有 this, 箭头函数的 this 是上下文的 this (你的箭头函数写在哪里 this 就决定了)
注意:我们在判断箭头函数的 this 是什么的时候, 可以从打印的这一行向上一行看但是因为上一行是在 对象 obj 的内部, 所以这个位置是不能书写 JS 代码的所以继续到 对象的上一行去看 this, 那就到了全局
箭头函数内部没有 this :
我们在判断箭头函数的 this 是什么的时候, 可以从打印的这一行向上一行看
但是因为上一行是在 对象 obj 的内部, 所以这个位置是不能书写 JS 代码的
所以继续到 对象的上一行去看 this, 那就到了全局, 所以这地方的 this fn1 箭头函数内部的 this
参数的默认值
- 参数的默认值 (以前就讲过, 只不过参数的默认值是 ES6 新增的)
- 其实就是对原本的普通函数写法上一个优化
注意点: 箭头函数的参数如果需要使用默认值, 那么不管有多少个形参, 都必须书写小括号
function fn(a = 100, b = 200) {
// 声明两个形参
// 其中a设置默认值为 100
// 其中b 设置默认值为200
console.log('a:', a);
console.log('b:', b);
}
// 两个实参都没有传递,都会只用默认值
fn(); //a: 100 b: 200
// 给 a 传递 实参2 b 不传递的实参
fn(2); // a: 2 b: 200
// 给 a 传递实参10 b 传递实参20
fn(10,20); // a: 10 b: 20
ES6 的展开运算符(扩展运算符)
- 作用 : 展开数组的[]或者 展开对象的{}
- 作用1: 常见的合并数; 将一个数组展开
- 作用2: 给函数传递参数
- 展开数组
console.log(100, 200, 300, 400,);
// 100 200 300 400
var arr =[100,200,300,400];
console.log(arr);
// [100, 200, 300, 400]
console.log(...arr);
100 200 300 400
相当于 将数组去掉 [] 即 console.log(100, 200, 300, 400,);
作用1 : 常见的合并数组
var arr1 = [11];
var arr2 = [22];
var arr3 = [33,44,55];
//需求 :将所有数组的数据合并在一起
var arr4 = [...arr1,...arr2,...arr3];
// 注意 之间用 , 相连
console.log(arr4);
[11, 22, 33, 44, 55]
var arr = [12, 15, 7, 8, 16, 20, 4];
// 需求 求数组里的最大值
// var max = Math.max(12, 15, 7, 8, 16, 20, 4)
// var max = Math.max(arr);
var max = Math.max(...arr)
console.log(max); //20
NaN 因为这里不认识数组 只能拿到NaN
20
var arr1 = [1, 2, 3, 4]
console.log(arr1); //[1, 2, 3, 4] 新数组
console.log(...arr1); //1 2 3 4 展开数组
console.log([...arr1]);//[1, 2, 3, 4] 新数组
- 展开对象
var obj = { name: "张三", age: 18 };
console.log(obj);// {name: '张三', age: 18}
console.log(...obj);
Uncaught TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function
报错 js不允许
作用1: 复制对象
注意:展开书写的顺序问题 在有相同成员的时候
var obj1 = {
sex: '男',
name: 'jeck',
...obj,
};
console.log(obj1);
{sex: '男', name: '张三', age: 18}
var obj2 = {
sex: '男',
...obj,
name: 'jeck',
};
console.log(obj2);
{sex: '男', name: 'jeck', age: 18}
- 函数传参
var arr = [100, 200, 300];
const fn = (a, b, c) => console.log(a,ba,c);
// fn(arr[0],arr[1],arr[2])
fn(...arr)
ES6中的解构赋值
- 快速从 “对象” 或 “数组” 中获取 “成员” (在开发中很常用,简单方便快捷)
- 解构赋值 分为 两种
- 数组的解构赋值
- 对象的解构赋值
- 数组的解构赋值
- 快速从数组中获取数据
- 注意结构数组用 []
- 按照索引进行匹配
- 对象的解构赋值
- 快速从对象中获取数据
- 注意结构数组用 {}
- 按照 键值对 进行匹配
// 1.1以前
let arr = [100, 200, 300,];
let a = arr[0]
let b = arr[1]
console.log(a, b);
//100 200
// 1.2 现在
arr = ['hello', 'world']
let [a, b] = arr
let [a,b] =['hello','world'];
// // 此时获取的 a 为 arr[0] b 为 arr[1]
console.log(a);//hello
console.log(b);// world
// 2.对象的解构赋值
// 快速从对象中获取数据
// 1.1 以前
var obj = {
name: '张三',
age: 18,
}
let name = obj.name
console.log(name); //张三
let age = obj.age
console.log(age);//18
// 1.2现在
var obj = {
name: '张三',
age: 18,
}
let { name, age, a } = obj;
// // 定义一个叫做 name 的变量, 获取的是 obj 内一个叫做 name 的成员的值
console.log(name);//张三 // var name = obj.name
console.log(age);//18 // var age = obj.age
console.log(a); //undefined // var a = obj.a
/**
* 前边的 {} 表明是解构赋值, 我需要从赋值号后边的 对象 obj(必须是对象)中
* 拿到 age 和 name 属性
*/
// 定义一个叫做 a 的变量, 获取的是 obj 内一个叫做 a 的成员的值
// 定义一个不一样的变量名
var { a } = obj; // var a = obj.a
console.log(a);//undefined
// 其实可以起一个别名
// 定义一个叫做a 的变量 , 获取的是obj 内一个 叫做 age 的成员的值
var { age: a } = obj // var a = obj.age
console.log(a);//18
模板字符串
- ES6中 新增的定义字符串的方式
- ES5 的时候字符串只能是 '' "" 包裹的内容
- 弊端: 字符串内不能换行, 拼接变量的时候不方便
- ES6 的模板字符串可以使用 `` 包裹, 内部如果需要添加变量, 可以书写一个 ${变量}
以前:
var str = ''
var str1 = ''
现在:
var str2 = `内容`
区别:
1.可以换行书写
2.可以在字符串内解析变量
=> 当你需要解析变量的时候,直接书写${你要解析的变量}
*/
var str1 = '1
23'
// 换行后打印会报错
// Uncaught SyntaxError: Invalid or unexpected token
var str1 = '1 23'
var str2 = '1 23'
/* var str3 = `1
23`
*/
// `` 打印时会保留原样的换行
console.log(str1);// 1 23
console.log(str2);// 1 23
console.log(str3);// 1 23
console.log(str2 === str1); // true
console.log(str3 === str1); // false
var age = 18;
var s1 = `我今年18岁`;
console.log(s1); //我今年18岁
console.log(`我今年${age}岁`); //我今年18岁
// 解析变量 时用 ${}
var s2 = '我今年${age}岁'
console.log(s2);// 我今年${age}岁
var s3 = "我今年${age}岁"
console.log(s3);// 我今年${age}岁
Set方法
- 类似于数组的东西,也是按照索引下标的排列方式但是不允许使用下标并且,不会出现重复的数据
const OSet = new Set([1, 2, 1, 2, 3, 4, 4,]);
console.log(OSet); // {1, 2, 3, 4}
// {1, 2, 3, 4}
/* 0:1
1:2
2:3
3:4
size:4
*/
// Set 中不允许使用下标
console.log(OSet[0]);
undefined
// size 类似数组的length
console.log(OSet.size);
//4
// 方法
// 1.add()
console.log(OSet.add(5));
// {1, 2, 3, 4, 5}
// 2. has()
console.log(OSet.has(2));
//true
// 3. delete()
console.log(OSet.delete(2));
//true
// 4. clear()
console.log(OSet.clear());
//undefined
console.log(OSet);
// {size: 0}
// 5. forEach()
OSet.forEach((value, index, origin) => {
/**
* 注意: 因为 set 中的索引只能看到, 但是不能使用
* 所以第二个参数 index 的值, 就和 第一个参数 value 一摸一样
*/
console.log(value, index, origin);
/*
1 1 Set(4) {1, 2, 3, 4}
2 2 Set(4) {1, 2, 3, 4}
3 3 Set(4) {1, 2, 3, 4}
4 4 Set(4) {1, 2, 3, 4}
*/
})
/**
* Map
*
* 和 Set 一样, 也是 ES6中新增的一个数据解构, 也是不支持重复数据
* 类似于 对象
* map 中的属性名可以是任意类型的
*/
const arr = [100]
const oMap = new Map([['600', '200'], [arr, '200']])
// 1. set() 作用: 添加数据
oMap.set('newKey', 100)
oMap.set('QF001', 200)
// 2. get() 作用: 获取到这个 key 对应的 value
console.log(oMap.get('QF001')) // 200
console.log(oMap.get('QF002')) // undefined
// 3. has() 作用: 查询数据解构中是否存在当前 key
console.log(oMap.has('QF002')) // false
console.log(oMap.has('newKey')) // true
// 4. delete() 作用: 删除数据结构中的某一项
oMap.delete('QF001')
// 5. clear() 作用: 清空
// oMap.clear()
console.log(oMap)
//Map(4) {'600' => '200', Array(1) => '200', 'newKey' => 100,}
// 6. forEach
oMap.forEach((value, key, origin) => {
// /**
// * value: 属性值
// * key: 对应的属性名
// * origin: 原本的数据结构
// */
console.log(value, key, origin)
/*
0 : {"600" => "200"}
1: {Array(1) => "200"}
2: {"newKey" => 100}
*/
})