1、环境对象this简述
环境对象 this : 谁 ‘调用’ this,this就指向谁 相当于中文中的 '我' , 谁说出来这个字,这个字就代表谁
2、this指向
- (1)普通函数: 函数名() this->window
- (2)构造函数: new 函数名() this->new创建的实例对象
- (3)对象方法: 对象名.方法名() this->对象
3、call apply bind 三者的区别
(1) call
语法: 函数名.call(修改的this,参数1,参数2………)
function fn( a , b ) {
console.log(this)
console.log(a + b)
}
// 函数名.call(修改的this,参数1,参数2………)
fn.call( { name: '张三' } , 10 , 20 )
- 应用场景1:万能数据类型检测
typeof 数据: 检测数据类型,但是有两种数据类型无法检测typeof无法检测 数组 与 null , 得到的都是object
let str = 'abc'
let num = 123
let bol = true
let und = undefined
let nul = null
//引用类型
let arr = [10,20,30]
let fn = function(){}
let obj = {name:'ikun'}
console.log( typeof str )//'string'
console.log( typeof num )//'number'
console.log( typeof bol )//'boolean'
console.log( typeof und )//'undefined' 未定义
console.log( typeof nul )//'object' 空值
console.log( typeof arr )//'object'
console.log( typeof fn )//'function'
console.log( typeof obj )//'object'
因此,call就派上用场了~~~~~~~~
- 万能数据类型检测: Object.prototype.toString.call( 数据 )
- (1)Object.prototype.toString() 内部会返回this的数据类型, 得到固定格式字符串
[object 数据类型]- (2)使用Object原型中的toString()要想得到数据类型,只需要把this修改成你想要检测的对象
上代码
console.log( Object.prototype.toString.call(str) )//'[object String]'
console.log( Object.prototype.toString.call(num) )//'[object Number]'
console.log( Object.prototype.toString.call(bol) )//'[object Boolean]'
console.log( Object.prototype.toString.call(und) )//'[object Undefined]'
console.log( Object.prototype.toString.call(nul) )//'[object Null]'
console.log( Object.prototype.toString.call(arr) )//'[object Array]'
console.log( Object.prototype.toString.call(fn) )//'[object Function]'
console.log( Object.prototype.toString.call(obj) )//'[object Object]'
- 可以改变函数内部的this指向
- 会调用函数, 并且改变函数内部this指向
- call是单个数据传参
(2) apply
//声明函数
function fn(a, b) {
console.log(this)
console.log(a + b)
}
//(1) 函数名.call(修改的this,参数1,参数2………)
fn.call({ name: '张三' }, 10, 20)
//(2) 函数名.apply(修改的this, 数组/伪数组 )
// apply会自动遍历数组和伪数组,然后逐一传参
fn.apply({ name: "李四" }, [50, 60] )
- 可以改变函数内部的this指向
- 会调用函数, 并且改变函数内部this指向
- apply是以数组类型进行传参
- 应用场景1:伪数组转真数组
//需求: 有时候伪数组 想要使用 真数组的方法 , 就需要把伪数组转成真数组
//(1)把伪数组的元素取出来, push到真数组中
let arr = []
// arr.push(obj[0], obj[1], obj[2])
// console.log(arr)
//(2)手动写循环遍历添加
// for (let i = 0; i < obj.length; i++) {
// arr.push(obj[i])
// }
//(3) arr.push.apply( arr,伪数组 )
//这里使用apply不是为了修改this,而是借助传参特点:自动遍历伪数组/数组传参. 所以第一个参数应该写arr(保持this不变)
arr.push.apply(arr,obj)
console.log( arr )
//ES6 : 伪数组转真数组,固定静态方法 Array.from( 伪数组 )
let newArr = Array.from( obj )
console.log( newArr )
- 应用场景2:求数组最大值
let arr = [20, 55, 60, 80, 100, 30, 40]
//(1)js基础 : 擂台思想
let max = arr[0]
for (let i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i]
}
}
console.log(max)
//(2)js高级 : Math.max()
// let max1 = Math.max(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6])
let max1 = Math.max.apply(Math, arr)
console.log(max1)
//ES6 : Math.max(...arr)
// ...功能类似于apply,也会自动的把数组给遍历
let max2 = Math.max(...arr)
console.log(max2)
(3) bind
//声明函数
function fn(a, b) {
console.log(this)
console.log(a + b)
}
//(1) 函数名.call(修改的this,参数1,参数2………)
fn.call({ name: '张三' }, 10, 20)
//(2) 函数名.apply(修改的this, 数组/伪数组 )
// apply会自动遍历数组和伪数组,然后逐一传参
fn.apply({ name: "李四" }, [50, 60])
//(3) 函数名.bind(修改的this)
// bind不会立即执行函数,而是得到一个修改this之后的新函数
let newFn = fn.bind({name:'王五'})
newFn(22,33)
- 应用场景1:修改定时器的this
//定时器中的this默认指向window,如果修改定时器的this,就需要使用bind
let fn = function (){
console.log(this)
}
let newFn = fn.bind({name:'111'})
setTimeout( newFn , 2000)
//上面步骤可以简写一行
setTimeout( function(){
console.log(this)
}.bind({name:'李四'}) , 2000 )
- 可以改变函数内部的this指向
- 不调用函数, 并且改变函数内部this指向
三者的区别(面试题)
相同点 :(1)都可以修改this指向不同点 :(1)传参方式不同 : call是单个传参, apply是数组/伪数组传参 (2)执行机制不同 : call和apply会立即执行函数, bind不会立即执行而是得到修改this的新函数
4.箭头函数this指向
1.箭头函数this :
- 箭头函数没有this
- 箭头函数中使用this, 本质是通过作用域链找上一级作用域的this
2.拓展:箭头函数没有this,对箭头函数影响
- (1)箭头函数不能作为构造函数
- (2)箭头函数不能修改this
- (3)事件处理函数一般不用箭头函数
let fn = ()=>{
//1级
console.log(this)
}
fn()//window
箭头函数经典面试题奉上
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()
后记
如果发现内有语句或逻辑混乱的地方,还请各路大神指正。