作用: call,apply,bind可以动态改变传入函数的this
使用: f.call(o,para1,para2…)
f.apply(o,[para1,para2…])
应用:
借用方法
var xm = { name: '小明', food: '饺子', cook: function() { console.log("我把" + this.food + "做好了"); } } var xl = { name: '小李', food: '方便面' } xm.cook(); xm.cook.call(xl); xm.cook.apply(xl);
实现继承
function Animal(name) { this.name = name; this.showName = function() { alert(this.name); } } function Cat(name) { Animal.apply(this, [name]); //Animal.call(this, name); } var cat = new Cat("咕咕"); cat.showName();
区别
call 和 apply 第一个参数都是一样的,这个参数将代表this指向的对象call 接收的参数 需要 一个个的 枚举出来apply 接收的参数, 可以直接是一个数组,也可以是类数组对象(arguments)
手写call
let obj1 = { value: 1 } let obj2 = { value: 2, getValue(name, age) { return { value: this.value, name: name, age: age } } }Function.prototype.myCall = function () { const fn = Symbol('fn') //用symbole声明一个独有的属性,防止覆盖已有属性 let ctx = arguments[0] || window // 如果没有this传入,默认绑定window对象 ctx.fn = this // 函数赋值(改变this执行);可以再次输出this,查看效果 let args = [...arguments].slice(1) // 获取传入的参数。这里为了下面方便判断,所以截去第一个参数(this),并且把剩余参数变为数组; let result = args.length > 0 ? ctx.fn(...args) : ctx.fn() // 执行当前函数 delete ctx.fn // 删除我们改写的fn属性。因为不能改变原有对象,我们只是改变this,执行完就删除 retun result // 返回结果}// 调用console.log('call方法改写', obj2.myCall(obj1,'小明',12))
步骤分解
语义分解: 上面函数调用call函数,内部代码就变成了这样
1. 会先判断当前是否有this,也就是是否是{}。2. 声明一个独有的属性,方便调用3. 改变this指向(函数赋值)4. 根据当前传入的参数个数,来判断执行函数所带的参数5. 删除改变的fn属性6. 返回结果// 调用前// let obj1 = {// value: 1// }// 调用后 let obj1 = { value: 1, getValue(name, age) { return { value: this.value, name: name, age: age } } }++++++++++++++++++++++++++++ let obj2 = { value: 2, getValue(name, age) { return { value: this.value, name: name, age: age } } }
代码分解
1. const fn = Symbol('fn')// Symbol 作为对象的属性名,可以保证属性不重名2. arguments: 任意一个函数的内部,都有一个arguments对象arguments作用:获取传递来的所有实参,他是一个类数组,类数组。l3. 类数组转化为数组的方法 [...argument] Array.from(arguments) Array.prototype. slice.call(arguments)
手写apply
let obj1 = { value: 1 } let obj2 = { value: 2, getValue(name, age) { return { value: this.value, name: name, age: age } } } Function.prototype.myApply = function () { const fn = Symbol('fn') let ctx = arguments[0] || window ctx.fn = this let args = [...arguments].slice(1) let result = args.length > 0 ? ctx.fn(...args) : ctx.fn() delete ctx.fn return result }// 调用console.log('call方法改写', obj2.myApplyl(obj1,'小明',12))
bind返回一个新的函数 ,所以需要重新调用一次