apply、call和bind的区别?
https://segmentfault.com/a/1190000018017796
都是可以改变 this 的指向的。
- apply 和 call 基本类似,他们的区别只是传入的参数不同。
- apply第二个对象是数组
- call多个参数平铺
- bind 是创建一个新的函数,必须要手动去调用。
func.apply(thisArg, [argsArray])func.call([thisArg[, arg1, arg2, ...argN]])let boundFunc = func.bind(thisArg[, arg1[, arg2[, ...argN]]])
执行结果/call
下面代码的输出是什么?
const person = { name: "Lydia" };function sayHi(age) {console.log(`${this.name} is ${age}`);}sayHi.call(person, 21);sayHi.bind(person, 21);
A: undefined is 21 Lydia is 21 B: function function
C: Lydia is 21 Lydia is 21 D: Lydia is 21 function
答案:D 原因:.call方法会立即执行!.bind方法会返回函数的拷贝值,
手写apply和call
myCall
Function.prototype.myCall = function (content) {const cxt = content || window;const args = Array.from(arguments).slice(1); // 类数组转换成数组const key = Symbol();cxt[key] = this; // 函数内部的this指向contentlet res = cxt[key](...args);delete cxt[key];return res;}
myApply
Function.prototype.myApply = function (context, args) {context = context || windowargs = args ? args : []const key = Symbol() //给context新增一个独一无二的属性以免覆盖原有属性context[key] = thisconst result = context[key](...args) //通过隐式绑定的方式调用函数delete context[key] //删除添加的属性return result}
手写bind
https://github.com/mqyqingfeng/Blog/issues/12
⚠️ 返回function
Function.prototype.myBind = function (context, ...args) {const fn = thisargs = args ? args : []return function newFn(...newFnArgs) {if (this instanceof newFn) {return new fn(...args, ...newFnArgs)}return fn.apply(context, [...args,...newFnArgs])}}
this的绑定方式优先级:箭头函数 -> new绑定 -> 显示绑定call/bind/apply -> 隐式绑定 -> 默认绑定
bind1:针对void 函数,简单的改变this指向
Function.prototype.ebind = function(obj) {const func = this;return function () {return func.call(obj);}}// 测试let obj = {name: 'Jack',};let myFunc = function () {console.log(`${this.name}`);};let newFunc = myFunc.ebind(obj)newFunc() // Jack
bind2: 针对多个参数函数,改变this指向
Function.prototype.ebind = function() {const func = this;const args = [...arguments];return function () {return func.call(...args);}}// 测试let obj = {name: 'Jack',};let myFunc = function (id) {console.log(`${this.name}, ${id}`);};let newFunc = myFunc.ebind(obj, 1287)newFunc() // Jack, 1287
bind3:
Function.prototype.ebind = function() {const func = this;const args = [...arguments];return function () {const _args = [...arguments];return func.call(...args, ..._args);}}// 测试let obj = {name: 'Jack',};let myFunc = function (...args) {console.log(`${this.name}, ${args.join(', ')}`);};myFunc.ebind(obj, 1278)('Cheng Du', '天府一街')// Jack, 1278, Cheng Du, 天府一街
bind4: 支持
Function.prototype.ebind = function() {const func = this;const args = [...arguments];return function Fn () {const _args = [...arguments];if (this instanceof Fn) {return new func(...args.slice(1), ..._args);}return func.call(...args, ..._args);}}// 测试let obj = {name: 'Jack',};let myFunc = function (...args) {console.log(`${this.name}, ${args.join(', ')}`);};let test1 = myFunc.ebind(obj, 1278);console.log(new test1('Cheng Du'));// Jack, 1278, Cheng Du
