持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第22天,点击查看活动详情
js重点知识
this的三种指向
this指向取决于函数的调用 , 函数有三种调用方式:
环境对象this : 谁'调用'我,我就指向谁
(1)普通函数 : 函数名() this指向window
(2)对象方法 : 对象名 . 方法名() this指向对象
(3)构造函数 : new 函数名() this指向new创建的实例对象
小技巧 : 没有new是window , 有new是实例对象 , 有点是点左边的对象
函数上下文模式
默认情况下 , 函数内部的this是无法被修改的
函数上下文作用 : 函数上下文模式 , 可以修改函数作用域内部this指向
语法 : 有3种写法call()
apply()
bind()
, 它们定义在Function构造函数的原型中 , 作用都是修改this指向 , 应用场景不同
call() apply() bind() //动态修改函数中的this指向
(1)函数名 . call (修改的this , agr1..., agr2...)
function fn(a, b) {
console.log(a + b) //50
console.log(this) //object
}
fn.call({name:小明},[20,30])
call 的应用场景 : 万能数据类型检测: Object . prototype . tostring . call(数据)
万能数据类型检测原理:
a. Object .prototype . tostring()内部会返回this的数据类型 , 得到固定格式字符串 '[object 数据类型]'
b . 使用object原型中的tostring()要想得到数据类型 , 只需要把this修改成你想要检测的对象
typeof 数据 : null和数组无法检测,结果都是 'object'
(2)函数名 . apply (修改的this , 数组或者伪数组)
apply会自动帮你遍历数组 , 然后按照顺序逐一传参
function fn(a, b) {
console.log(a + b) //50
console.log(this) //object
}
fn.apply({name:小明},[20,30]) //
apply的应用场景一 : 伪数组转真数组
//伪数组 本质是 : 对象 let obj = { 0:20, 1:66, 2:88, 3:90, length:4 } //伪数组转真数组 let arr = [] //借助 apply自动遍历数组/伪数组 逐一传参特点 arr.push.apply( arr,obj ) console.log(arr) //[20,66,88,90] //伪数组转真数组 : Array.from( 伪数组 ) console.log( Array.from(obj) )
ES6新语法:伪数组转真数组 Array.from(伪数组)
apply的应用场景二 : 求数组的最大值
const arr = [10,20,30] 求最大值: Math.max() const max1 =Math.max.apply(Math,arr) console.log(max1) //30 ...展开运算符求最大值 const max = Math.max(...arr) console.log(max) //30
ES6新语法:求数组的最大值 Math.max(...arr) ...展开运算符
(3)函数名 . bind(修改后的this)
bind不会立即执行函数 , 而是返回一个修改this之后的新函数
function fn(a,b){
console.log( a + b )
console.log( this )
}
const newFn = fn.bind({name:小明})
newFn(10,20) //30 Object
(4)call()
apply()
bind()
三者区别
相同点 : 作用一致,修改函数this指向
不同点 : a . 传参方式不同 : call是按照顺序传参, apply是数组/伪数组传参
b . 执行机制不同:call和apply会立即执行函数,而bind不会立即执行而是得到修改this的新函数
闭包(重点)
(1)闭包closure是什么?
闭包是一个访问其他函数内部变量的函数
闭包 = 函数 + 上下文引用
(2)闭包的作用 : 解决变量污染 , 让变量被函数保护起来
在实际开发中 , 闭包是一种现象,一般出现在回调函数中
function fn() {
let count = 0
setInterval(function () {
console.log(count++)
}, 1000)
}
代码改写 add + count 构成了闭包
function fn() {
let count = 0
function add() {
console.log(count++)
}
setInterval(add, 1000)
}
递归
(1)递归函数 : 在函数中调用自己
a. 递归类似于循环一定要有结束条件,否则会导致死循环
b. 能用递归函数实现的需求,就一定可以用循环调用函数来解决,只是代码简洁与性能不同而已
let i = 1
function fn(){
console.log('123') //打印3次123
i++
if(i<=3){
fn()
}
}
fn()
(2)递归应用 :
a . 浅拷贝和深拷贝
b . 遍历DOM树
浅拷贝和深拷贝
浅拷贝 : 拷贝地址 , 修改拷贝后的数据对原结构会有影响
深拷贝 : 拷贝数据 , 修改拷贝后的数据对元数据没有影响
深拷贝两种方式
(1) josn方式 : let newObj = JSON.parse( JOSN.stringify(js对象))
(2)递归方式实现深拷贝
let obj = {
name: '张三',
age: 20,
sex: '男',
hobby: ['吃饭', '睡觉', '学习'],
student: {
name: "班长",
score: 90
}
}
// 深拷贝 递归方式
// (1)创建一个空对象
let newObj = {}
// (2)调用函数拷贝
// 封装函数
function kaobei(newObj, obj) {
// 遍历对象,把obj里面的数据拷贝给newObj
for (let key in obj) {
// 判断是不是数组,如果是数组就需要继续遍历
if (obj[key] instanceof Array) {
newObj[key] = [] //是数组就先声明一个空数组
// 递归遍历数组 重新传参
kaobei(newObj[key], obj[key])
} else if (obj[key] instanceof Object) {
newObj[key] = {} //是数组就先声明一个空数组
// 递归遍历数组 重新传参
kaobei(newObj[key], obj[key])
} else {
newObj[key] = obj[key]
}
}
}
kaobei(newObj, obj)
console.log(newObj, obj);
newObj.hobby[0] = '游戏'
newObj.student.name = '111'
ES6新语法
解构赋值语法
对象解构赋值
其实就是变量赋值的简写
取出对象的属性 赋值给 变量
let obj = {
name: '张三',
age: 20,
sex: '男'
}
//解构变量赋值
let {name,age,sex} = obj
数组解构赋值
取出数组的元素 赋值给变量
let arr = [10, 20, 30]
//解构数组赋值
let [n1,n2,n3] = arr
函数参数解构
当函数参数是对象类型,就可以对形参进行解构
ES6 :函数传参
function fn1({name,age,sex}){
//声明三个变量接收对象的参数值
console.log(name,age,sex);
};
fn1({
name:'小明',
age:32,
sex:'男'
})
箭头函数
- 什么事箭头函数?
箭头函数相当于function函数的简写 , 把function改成=> , 然后把形参()写在箭头的左边
-
语法:
箭头函数 let fn = (a,b)=>{ console.log(a+b) } fn(10,20) (1)如果箭头函数形参只有一个,则可以省略形参小括号 let fn1 = a => { return a*2 } let res1 = fn1(55) console.log(res1) (2)如果函数体只有一行代码,则可以省略大括号(此时必须要省略return) let fn2 = a => a*2 let res2 = fn2(55) console.log(res2)
箭头函数语法注意点:
(1)如果箭头函数形参只有一个,则可以省略形参小括号
(2)如果函数体只有一行,则可以省略大括号{}, 此时 必须要省略return
箭头函数this指向
-
function函数this有三种指向 :
普通函数: 函数名() this->window
对象方法: 对象.方法名() this->对象
构造函数: new 函数名() this->new创建的实例
-
箭头函数this : 箭头函数没有this
箭头函数中使用this, 本质是通过作用域链找上一级作用域的this
-
箭头函数没有this,对箭头函数影响
(1)箭头函数不能作为构造函数
(2)箭头函数不能修改this
(3)事件处理函数一般不用箭头函数
-
箭头函数面试题
let obj = { name: 'ikun', eat() { //1级 this : function函数指向对象obj function fn1() { //function函数this取决于调用 函数名() this->window console.log(this)//window } fn1() let fn2 = () => { //2级 //this:箭头函数,访问上级1级this console.log(this)//obj } fn2() }, learn: () => { //1级 this箭头函数,访问上级 window function fn1() { //function函数this取决于调用 函数名() this->window console.log(this)//window } fn1() let fn2 = () => { //2级 this箭头,访问上级1级的this -> window console.log(this)//window } fn2() } } obj.eat() obj.learn()
展开运算符 ...
-
定义:相当于遍历 数组/对象的 简写
-
应用 :
(1)连接数组
let arr1 = [10,20,30] let arr2 = [40,50,60] let arr3 = [70,80,90] 连接数组 arr1.push(...arr2,...arr3) consoloe.log(arr1) //[10,20,30,40,50,60,70,80,90]
(2)求数组最大值
let arr = [20,50,66,80,100,40] 求最大值 let max = Math.max(...arr) console.log(max) //100
数据类型Set
-
数据类型Set是什么?
它是一个集合 , 相当于数组,唯一的区别是 Set不能存储重复元素
-
应用场景 : 数组去重
数组去重固定语法 let newArr = [ ...new Set(数组) ] let arr = [10, 10, 20, 30, 20, 30, 50, 60, 70, 50] //需求:除去数组中重复的元素 let newArr = [...new Set(arr)] console.log(newArr) //[10, 20, 30, 50, 60, 70]