call:
先看使用方法
var obj = {
name: "小明"
}
var name = "小红"
function print(sex) {
console.log(this.name)
console.log(this)
console.log(sex)
}
print('女');//小红,window,女。如果严格模式下this会是undefind,所以会报错
print.call(obj,'男');//小明,obj,男
可以看到this的值已经被改变了。在没使用call之前指向的是window(因为是非严格模式,默认指向window)。 下面尝试自己实现这个功能:
Function.prototype.myCall = function() {
//判断调用此方法的是不是一个函数,不是的话就抛出错误
if (typeof this !== 'function') {
throw new TypeError('请用函数调用')
};
//然后获取传入的需要改变指向的this对象。
var args=[...arguments];//这里使用了es6的语法
var context =args.shift() || window;
//将当前函数挂载到传入的对象上
var fn = Symbol('fn'); // 我们声明一个独一无二的属性
context[fn] = this;
//执行函数
var res = context[fn](...args);
//因为传入的对象上没有fn这个函数,所以执行完了需要删掉
delete context[fn];
//返回执行结果
return res;
}
接下来试试我们自己实现的call
var obj = {
name: "小明"
}
var name = "小红"
function print(sex) {
console.log(this.name)
console.log(this)
console.log(sex)
}
print('女');//小红,window,女。
print.myCall(obj,'男');//小明,obj,男
apply
apply的使用方法与call其实是一样的。但是区别在于传参的时候,传的是一个数组
var obj = {
name: "小明"
}
var name = "小红"
function print(sex) {
console.log(this.name)
console.log(this)
console.log(sex)
}
print('女');//小红,window,女。
print.apply(obj,['男']);//小明,obj,男
接下来我们自己实现:
Function.prototype.myApply=function(){
if (typeof this !== 'function') {
throw new TypeError('请传入一个函数')
};
var args = [...arguments];
var context = args.shift() || window;
var fn = Symbol('fn');
context[fn] = this;
var res = context[fn](...args[0]);//这里就是和call不一样的地方,因为args[0]就是传入的参数数组
delete context[fn];
return res;
}
使用自己实现的apply:
var obj = {
name: "小明"
}
var name = "小红"
function print(sex) {
console.log(this.name)
console.log(this)
console.log(sex)
}
print('女');//小红,window,女。
print.myApply(obj,['男']);//小明,obj,男
bind
bind方法的作用也是改变this的指向。但是与call和apply有不一样的地方,此方法返回的是一个函数,不会立即执行,需要我们自己去执行。并且可以分两次传参。使用方法如下:
var obj = {
name: "小明"
}
var name = "小红"
function print(age, sex) {
console.log(this.name)
console.log(this)
console.log(age)
console.log(sex)
}
print(20,'女') //小红,window,20,女
var bindPrint = print.bind(obj,18)
bindPrint("男") //小明,obj,18,男
可以看到this的指向已经变了。并且传参可以分次或者一次性传完。接下来我们试试自己实现这个方法:
Function.prototype.myBind = function() {
var self = this; //将函数存起来
//关于call和apply的使用与自己实现,上面我们已经实现过了。这里就不再重复相关的过程。直接使用
var context = [].shift.call(arguments); //获取传入的this
var args = [].slice.call(arguments) //剩余的参数转为数组
return function() { //返回一个新的函数.需要再次调用一次改变this后的函数
var args2 = [].slice.call(arguments)//这里将第二次的参数保存起来
return self.apply(context, args.concat(args2))//返回函数执行的结果
}
}
运行自己实现的bind方法:
var obj = {
name: "小明"
}
var name = "小红"
function print(age, sex) {
console.log(this.name)
console.log(this)
console.log(age)
console.log(sex)
}
print(20,'女') //小红,window,20,女
var bindPrint = print.myBind(obj,18)
bindPrint("男") //小明,obj,18,男
以上