本文已参与[新人创作礼]活动,一起开启掘金创作之路
一.描述及各自相同和不同
1.默认情况下,函数有三种调用方式
普通函数: 函数名() -> this指向window
对象方法: 对象名.方法名() -> this指向对象
构造函数: new 函数名() -> this指向new创建的实例对象
2.函数三种调用方式有一个共同点: this指向无法修改
3.函数上下文调用 : 用于修改函数中的this指向
3.1 函数名.call(修改this,形参1,形参2...)
3.2 函数名.apply(修改this, 数组/伪数组 )
3.3 函数名.bind(修改this)
4. call和apply和bind区别
4.1 传参方式不同 : call是逐一传参, apply是数组/伪数组 传参方式不同
4.2 执行机制不同 : call和apply立即执行函数, bind不会立即执行函数
* call和apply用一次,改一次
* bind修改一次,终生有效
二. call
1.简单使用
function fn(a,b){
console.log( this )
console.log(a+b)
}
//普通函数 调用函数
fn(10,20)
//上下文调用 : 函数名.call(修改this,形参1,形参2...)
fn.call({name:'张三'},30,40)
输出结果
2. 使用场景
1. typeof 数据 : 检测数据类型
* 有两种数据类型无法检测 : null 和 array
2. 万能数据类型检测 : Object.prototype.toString.call( 数据 )
上代码
//值类型(基本数据类型)
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:'张三'}
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]'
输出结果
三. apply
基本使用
function fn(a,b,c){
console.log( this )
console.log(a+b)
}
//普通函数 调用函数
fn(10,20,30)
//(1) 函数名.call(修改this,形参1,形参2...)
fn.call({name:'张三'},30,40,50)
//(2) 函数名.apply(修改this,数组/伪数组)
// apply自动遍历数组/伪数组, 然后按照元素顺序逐一传参
fn.apply({name:'李四'},[30,40,50] )
输出结果
使用场景1 伪数组转真数组
伪数组
有数组三要素,但是没有数组的方法
伪数组本质 : 对象类型
使用
let weiArr = {
0 : 20,
1 : 30,
2 : 40,
length:3
}
console.log( weiArr )
//伪数组转真数组 : 伪数组如果想要调用真数组的方法,就可以把伪数组转成真数组
//ES5 : apply
let arr1 = []
//细节: 这里使用apply不是为了修改this,而是借助apply传参的特点(自动遍历伪数组传参)
//apply后面传arr1作用:保持this不变。 因为arr1.push()默认this就是arr1,这里不需要修改this
arr1.push.apply(arr1,weiArr)
console.log(arr1)
//ES6 : Array.from(伪数组)
let arr = Array.from(weiArr)
console.log(arr)
输出结果
使用场景2 求数组最大值
let arr = [80,100,99,20,50]
//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高级写法
let max1 = Math.max.apply(Math,arr)
console.log( max1 )
//ES6
// ...是ES6新增的一种运算符,类似于apply也会自动遍历arr,然后逐一传参
let max2 = Math.max(...arr)
console.log(max2)
输出结果
bind
基本使用
function fn(a, b, c) {
console.log(this)
console.log(a + b)
}
//普通函数 调用函数
fn(10, 20, 30)
//(1) 函数名.call(修改this,形参1,形参2...)
fn.call({ name: '张三' }, 30, 40, 50)
//(2) 函数名.apply(修改this,数组/伪数组)
// apply自动遍历数组/伪数组, 然后按照元素顺序逐一传参
fn.apply({ name: '李四' }, [30, 40, 50])
//(3) 函数名.bind(修改this)
// bind不会立即调用函数,而是得到一个修改this之后的新函数
// bind一般用于修改不会立即执行的函数中的this : 定时器、事件处理函数
let fn1 = fn.bind({ name: '王五' })
fn1(6,7)
//定时器中的this默认指向window
setTimeout( function(){
console.log(this)
}.bind({name:'王五'}) , 3000)
输出结果
注意
1. 上下文调用call apply bind修改 this指向
2. this:环境对象
3.注意点是 : 修改this必须是引用类型,如果是 string、number、boolean,则js编译器会自动帮你转成
对应的对象。 如果是undefined和null,则修改无效
function fn() {
console.log(this)
}
fn.call('abc')//new String('abc')
fn.call(123)//new Number(123)
fn.call(true)//new Boolean(true)
fn.call(undefined)//window
fn.call(null)//window
fn.call()//window