共计 4211 个字符,预计需要花费 11 分钟才能阅读完成。
三者的异同点?
应用办法
函数.call(对象,arg1,arg2….)
函数.apply(对象,[arg1,arg2,…])
函数.bind(对象,arg1,arg2,….)
相同点
都能够扭转 this 的指向,且第一个参数都是 this 将要指向的对象。
不同点
call 和 apply 在应用时会主动执行函数,而 bind 不会执行。
你能够本人手动实现三种办法吗?
bind 办法
概念:返回一个原函数的拷贝(也称绑定函数),在调用时设置 this
关键字为提供的值。并在调用新函数时,将给定参数列表作为原函数的参数序列的前若干项。
function.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
: 调用绑定函数时作为this
参数传递给指标函数的值。如果应用new
运算符结构绑定函数,则疏忽该值。当应用bind
在setTimeout
中创立一个函数(作为回调提供)时,作为thisArg
传递的任何原始值都将转换为object
。如果bind
函数的参数列表为空,执行作用域的this
将被视为新函数的thisArg
。arg1, arg2, ...
: 当指标函数被调用时,事后增加到绑定函数的参数列表中的参数。
举例说明:
window.value = 3; | |
var foo = {value:1}; | |
function bar() {console.log(this.value); | |
} | |
bar(); // 3 | |
bar.call(foo); //1 | |
// 指定函数 this 绑定为 foo, 产生一个新函数,之后再运行的时候,外部的 this 就是被绑定的对象 | |
var bindFoo = bar.bind(foo); | |
setTimeout(function() {bindFoo(); | |
},2000) | |
// 2 秒后打印 1 |
这个例子能够很好的了解 bind
的使用:
bar()
间接调用函数,其中的value
指的是全副变量value = 3
bar.call(foo)
这里应用call
立即扭转了bar
中的this
指向为foo
中bind
罕用于异步,在setTimeout
中,设置的工夫内,bar
的this
保留着指向foo
,所以两秒后打印 1,不是 3。
前置常识:
MDN:绑定函数也能够应用 new 运算符结构,它会体现为指标函数曾经被构建结束了似的。提供的 this 值会被疏忽,但前置参数仍会提供给模仿函数。
特地阐明:绑定函数被 new
实例化之后,须要继承原函数的原型链办法,且绑定过程中提供的 this 被疏忽(继承原函数的 this 对象),然而参数还是会应用
代码实现
const wang = { | |
age: 18, | |
love: 'coding', | |
hello: function (age, love) {if (age) this.age = age; | |
if (love) this.love = love; | |
console.log("hello world, i am ghostwang," + this.age + "," + this.love); | |
} | |
}; | |
const ye = { | |
age: 19, | |
love: 'sleeping' | |
}; | |
// wang.hello.myCall(ye, 0); | |
Function.prototype.myBind = function () {if (typeof this !== 'function') {throw new TypeError(this + 'must be a function'); | |
} | |
const target = Array.from(arguments)[0]; // 第一个参数是 this | |
const args = Array.from(arguments).slice(1); | |
const self = this; | |
let fBound = function () { | |
const _this = this instanceof self ? this : target; // 检测是否应用 new 创立 | |
return self.apply(_this, args); | |
} | |
/** 假如咱们将调用 bind 的函数称为 C,将 fBound 的 prototype 原型对象指向 C 的 prototype 原型对象(上例中就是 self),这样的话如果将 fBound 作为构造函数(应用 new 操作符)实例化一个对象,那么这个对象也是 C 的实例,this instanceof self 就会返回 true。这时就将 self 指向新创建的对象的 this 上就能够达到原生 bind 的成果了(不再固定指定的 this)。否则,才应用 oThis,即绑定指定的 this。**/ | |
if (this.prototype) {fBound.prototype = this.prototype} | |
return fBound; | |
} | |
const foo = wang.hello.myBind(ye); | |
const foo2 = wang.hello.myBind(ye, 10, 'mom love u'); | |
const nFoo = new foo2(); // hello world, i am ghostwang,10,mom love u | |
foo(); // hello world, i am ghostwang,19,sleeping |
call 办法
概念:function.call(thisArg, arg1, arg2, ...)
;
thisArg
: 在 fun 函数运行时指定的this
值。须要留神的是,指定的this
值并不一定是该函数执行时真正的this
值,如果这个函数处于非严格模式下,则指定为null
和undefined
的this
值会主动指向全局对象 (浏览器中就是 window 对象),同时值为原始值(数字,字符串,布尔值) 的this
会指向该原始值的主动包装对象。arg1, arg2, ...
: 指定的参数列表。
var obj = {name:'segmentfault'}; | |
function fn() {// console.log(this); | |
console.log(this.name); | |
} | |
fn(); // undefined | |
fn.call(obj); // segmentfault |
了解:首先寻找 call
办法,通过原型链的查找,在 Function.prototype
上找到 call
办法;而后,扭转 fn
函数中的 this
指向,将 fn
执行。
var obj = {name:'wc'}; | |
function fn(age, country) {console.log(this.name + '-' + age + '-' + country); | |
} | |
fn.call(obj, 18, 'China'); // wc-19-China |
了解:带参数传入,参数须要开展,这也是惟一于 apply
办法不同的中央。
代码实现
Function.prototype.myCall = function () {const argumentsArr = Array.from(arguments); | |
const target = argumentsArr[0]; | |
if (!target) { // 判断是 node 还是浏览器环境 | |
target = typeof window === undefined ? global : window; | |
} | |
target.fn = this; // 这里的 this 指向的是. 后面的对象, 也就是被调用的函数的原型对象 | |
// 当初 taget 的 fn 属性就是缓存了被调用的函数, 须要扭转这个函数的外部 this,. 后面是谁,this 就指向谁, 所以当初 this 是 taget | |
const res = target.fn(argumentsArr.slice(1)); | |
delete target.fn; | |
return res; | |
} | |
const wang = { | |
age: 18, | |
love: 'coding', | |
hello: function () {console.log("hello world, i am zhou," + this.age + "," + this.love); | |
} | |
}; | |
const ye = { | |
age: 19, | |
love: 'sleeping' | |
}; | |
wang.hello.myCall(ye); // hello world, i am ghostwang,19,sleeping |
总结:
call
办法的第一个参数用于扭转 调用call
办法的函数内,this
的指向 ,然而如果传入null/undefined
值,此this
会指向window
call
办法须要把实参依照形参的个数传进去call
办法最初会应用参数去执行call
函数体内this
所指向的函数,个别是指向 调用call
的函数
apply 办法
概念:调用一个具备给定 this
值的函数,以及作为一个数组(或相似数组对象)提供的参数。
func.apply(thisArg, [argsArray])
thisArg
: 可选的。在func
函数运行时应用的this
值。请留神,this
可能不是该办法看到的理论值:如果这个函数处于非严格模式下,则指定为null
或undefined
时会主动替换为指向全局对象,原始值会被包装。argsArray
:可选的。一个数组或者类数组对象,其中的数组元素将作为独自的参数传给func
函数。如果该参数的值为null
或undefined
,则示意不须要传入任何参数。
代码实现
const wang = { | |
age: 18, | |
love: 'coding', | |
hello: function () {console.log("hello world, i am zhou," + this.age + "," + this.love); | |
} | |
}; | |
const ye = { | |
age: 19, | |
love: 'sleeping' | |
}; | |
Function.prototype.myApply = function () {const argumentsArr = Array.from(arguments); | |
const target = argumentsArr[0]; | |
if (!target) { // 判断是 node 还是浏览器环境 | |
target = typeof window === undefined ? global : window; | |
} | |
target.fn = this; // 这里的 this 指向的是. 后面的对象, 也就是被调用的函数的原型对象 | |
// 当初 taget 的 fn 属性就是缓存了被调用的函数, 须要扭转这个函数的外部 this,. 后面是谁,this 就指向谁, 所以当初 this 是 taget | |
const res = target.fn(...argumentsArr.slice(1)); | |
delete target.fn; | |
return res; | |
} | |
wang.hello.myApply(ye); // hello world, i am zhou,19,sleeping |
正文完
发表至: javascript
2021-08-03