apply() & call() & bind() 异同
同:用于改变函数中this 的指向
异:apply()和call()使用传参不同;apply()和call()可以实现函数调用,而bind()不能
function fn(a, b) {
console.log(this);
console.log(a, b);
}
var obj = {
a: 10
}
//fn.call(obj,1,2);
// apply()
//fn.apply(obj,[1,2]);
// bind()可以改变函数中this指向 但它不会调用函数
// 返回由指定this值和初始化参数改造的原函数拷贝,原函数不受影响
var newFn = fn.bind(obj, 1, 3);
newFn();
//apply()第二种使用场景
var arr = [10, 12, 45, 38];
var max = Math.max.apply(null, arr);
console.log(max);
bind()案例:
<body>
<button id='btn'>接受验证码</button>
<script>
var btn = document.querySelector('#btn');
var num = 10;
btn.onclick = function() {
//var that = this;
this.innerHTML = '剩余时间'+num + "s";
setInterval(function() {
num--;
this.innerHTML = '剩余时间'+num + "s";
}.bind(this),1000);
}
</script>
</body>
手写bind
// 1 函数可以在bind的时候传递一部分参数,在执行函数的时候又传递一部分参数
// 2 当 bind 返回的函数作为构造函数的时候,bind 时指定的 this 值会失效,但传入的参数依然生效
Function.prototype.bind1 = function (othis) {
if (typeof this !== 'function') {
throw new TypeError('bind function error');
}
var args = Array.prototype.slice.call(arguments, 1), // 获取bind函数从第二个参数到最后一个参数,即为传递的参数
_this = this;
// return function () {
// return _this.apply(othis || window, args.concat(Array.prototype.slice.call(arguments)));
// }
var bound = function() {
var bindArgs = Array.prototype.slice.call(arguments);
// 当作为构造函数时,this 指向实例,_this指向绑定函数,因为下面一句 `fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为 绑定函数的 prototype,此时结果为 true,当结果为 true 的时候,this 指向实例。
// 当作为普通函数时,this 指向 window,_this指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的 context。
_this.apply(this instanceof _this ? this : obj, args.concat(bindArgs))
}
// 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承函数的原型中的值
var Fn = function() {};
Fn.prototype = this.prototype;
bound.prototype = new Fn();
return bound;
}
手写call
Function.prototype.call1 = function(obj) {
var obj = obj || window;
obj.fn= this;
var args = [];
for(var i=1, len=arguments.length; i<len; i++) {
args.push(`arguments[${i}]`);
}
var result = eval(`obj.fn(${args})`)
delete obj.fn;
return result;
}
手写apply
Function.prototype.apply1 = function(obj, arr) {
var obj = Object(obj) || window;
obj.fn = this; // obj上新增一个function fn() {} 此函数就为调用apply的函数。 后续再调用
var result;
if(!arr) {
result = obj.fn();
} else {
var args = [];
for(var i=0, len=arr.length; i<len; i++) {
args.push('arr[' + i + ']');
}
result = eval('obj.fn(' + args + ')')
}
delete obj.fn;
return result;
}