三者的相同点:执行函数,可以改变this的指向
一、语法
1. call
function.call()
把找到的
call
方法执行
当call
方法执行的时候,内部处理了一些事情
1.首先把要操作的函数中的this关键字变为call
方法第一个传递的实参
2.把call
方法第二个及之后的实参获取到
3.把要操作的函数执行,并且把第二个以后传递进来的实参传递给函数
call()的第一个参数是this要指向的对象,后面传入的是参数列表,参数可以是任意类型,
- 非严格模式下,当第一个参数为null、undefined的时候,默认指向window;
"use strict"
let fn = function(a,b){
console.log(this,a,b);
}
let obj = {name:"obj"};
fn.call(obj,1,2); // this:obj a:1 b:2
fn.call(1,2); // this:1 a:2 b=undefined
fn.call(); // this:undefined a:undefined b:undefined
fn.call(null); // this:null a:undefined b:undefined
fn.call(undefined); // this:undefined a:undefined b:undefined
- 严格模式下,第一个参数是谁,this就指向谁,包括null和undefined,如果不传参数this就是undefined
"use strict"
let fn = function(a,b){
console.log(this,a,b);
}
let obj = {name:"obj"};
fn.call(obj,1,2); // this:obj a:1 b:2
fn.call(1,2); // this:1 a:2 b=undefined
fn.call(); // this:undefined a:undefined b:undefined
fn.call(null); // this:null a:undefined b:undefined
fn.call(undefined); // this:undefined a:undefined b:undefined
2.apply
apply:和call基本上一致,唯一区别在于传参方式
apply把需要传递给fn的参数放到一个数组(或者类数组)中传递进去,虽然写的是一个数组,但是也相当于给fn一个个的传递
fn.call(obj, 1, 2);
fn.apply(obj, [1, 2]);
3.bind
bind:语法和call一模一样,区别在于立即执行还是等待执行,bind不兼容IE6~8
fn.call(obj, 1, 2); // 改变fn中的this,并且把fn立即执行
const newFn = fn.bind(obj, 1, 2); // 改变fn中的this,fn并不执行,返回一个绑定新this的函数
newFn();
4.应用
在判断数据类形式使用typeof,一般不是太准确的,我们可以使用Object原型链顶端的toString()方法,即Object.prototype.toString.call()方法来判断一个数据的数据类型
function getType(data){
//区分对象类型 确定当前的数据的类型
const context = Object.prototype.toString.call(data); // "[object String]"
const type = context.slice(8, -1).toLowerCase();
return type ;
}
console.log(getType("a")); //string
二、实现
1.Call
/**
* @param context 上下文this对象
* @param args 动态参数
*/
Function.prototype.MyCall = function(context, ...args) {
context = context || window
// 防止覆盖掉原有属性
const key = Symbol()
// // 把this存到context[key],这里的this是调用的函数
context[key] = this
// 执行调用的函数,this指向context
const result = context[key](...args)
// 调用完删除context[key]
delete context[key]
return result
}
// 验证样例
function fun(arg1, arg2) {
console.log(this.name)
console.log(arg1 + arg2)
}
const obj = { name: 'Kite' }
fun.MyCall(obj, 1, 2) // Kite 3
2. apply
/**
* Apply实现
* @param context 上下文this对象
* @param args 参数数组
*/
Function.prototype.MyApply = function(context, args) {
context = context || window
const key = Symbol()
context[key] = this
const result = context[key](...args)
delete context[key]
return result
}
function fun(arg1, arg2) {
console.log(this.name)
console.log(arg1 + arg2)
}
const obj= { name: 'Kite' }
// 参数为数组;方法立即执行
fun.MyApply(obj, [1, 2, 3]) // Kite 6
3.bind
/**
* 自定义bind实现
* @param context 上下文
* @returns {Function}
*/
Function.prototype.MyBind = function(context) {
context = context || bind
return (...args) => {
this.call(context, ...args)
}
}
function fun(arg1, arg2) {
console.log(this.name)
console.log(arg1 + arg2)
}
const obj= { name: 'Kite' }
// 参数为数组;方法立即执行
const result = fun.MyBind(obj, 4, 5)
console.log(result()) // Kite 9