call、apply、bind的区别、使用、手写实现
call、apply、bind都是改变this指向的方法
call、apply都是直接调用的
call第一个参数传入指定的上下文,其他参数接在后面一个个传入;apply第一个参数传入指定的上下文,其他参数以数组形式接在后面传入
bind返回一个函数,需要自己去调用
-
call
示例
const person = { name:'小明', keep(age,school){ console.log(`${this.name}今年${age}岁,上${school}`) } } const student = { name:'小红', } person.keep(18,'大学') // 小明今年18岁,上大学 person.keep.call(student,10,'小学') // 小红今年10岁,上小学
手写实现
Function.prototype.myCall = function (context,...args){ // 1.模仿传参方式 context = context || window // 2.判断一下传入的上下文是否存在,若不存在就指向window const symbol = Symbol() // 3.用Symbol()取一个独一无二的值 context[symbol] = this // 4.使用symbol值绑定this,为了避免重名 const res = context[symbol](...args) // 5.调用函数并存下返回值 delete context[symbol] // 6.使用完删除 return res // 7.返回值 } person.keep.myCall(student,10,'小学')
-
apply
示例
const person = { name:'小明', keep(age,school){ console.log(`${this.name}今年${age}岁,上${school}`) } } const student = { name:'小红', } person.keep(18,'大学') person.keep.apply(student,[10,'小学'])
手写实现
// 和call几乎一样,只有传参有区别 Function.prototype.myApply = function (context,args){ // 第二个参数本身就是数组 context = context || window const symbol = Symbol() context[symbol] = this const res = context[symbol](...args) // 使用扩展运算符,将参数一个个传入 delete context[symbol] return res }
-
bind
示例
const person = { name:'小明', keep(age,school){ console.log(`${this.name}今年${age}岁,上${school}`) } } const student = { name:'小红', } person.keep(18,'大学') person.keep.bind(student)(10,'小学')
手写实现
Function.prototype.myBind = function (context,...args){ // ...args绑定时传的参数 context = context || window const symbol = Symbol() context[symbol] = this return function (...innerArgs){ // 返回的是个函数;...innerArgs调用时传的参数 context[symbol](...args,...innerArgs) delete context[symbol] } } person.keep.myBind(student,10)('小学')