回顾一下 this 是什么?
this 是指包含它的函数作为方法被调用时所属的对象。简单拆成三句话就是:
- 包含它的函数
- 作为方法被调用
- 所属的对象
改变 this 指向的函数 bind、call、apply
- 共同点
- 目标函数调用时,改变 this 指向为指定的值。
- 三个方法都是函数的方法,挂载在 Funtion.prototype 上
- 不同点
- 目标函数调用 call、apply 会直接被执行。
- 目标函数调用 bind 时,不会立即执行。而是返回一个新的函数,调用新函数才会执行目标函数。
回顾 bind、call、apply 的使用
<body>
<button class="btn">生长</button>
<script>
{
var btn = document.querySelector(".btn");
var name = "windows";
var obj = {
name: "Linux",
num: 0,
updateNum: function(){
this.num++;
console.log(this.num) // 1,2,3,4
}
}
function fn(){
console.log(this.name);
};
btn.addEventListener("click", obj.updateNum.bind(obj))
fn(); // windows
fn.call(obj); // Linux
fn.apply(obj) // Linux
fn.bind(obj)(); // Linux
}
</script>
</body>
回顾 bind、call、apply 的参数使用。
let name = "wanna";
let age = 20;
let obj = {
name: "hurt",
objAge: this.age,
objFn: function(a, b){
console.log(this.name + "年龄" + this.age, "性别:" + a + "兴趣爱好" + b);
}
};
let user = {
name: "hico",
age: 18
};
obj.objFn.call(user, "男", "篮球"); // hico年龄18 性别:男 兴趣爱好篮球
obj.objFn.apply(user, ["男","足球"]); // hico年龄18 性别:男 兴趣爱好足球
obj.objFn.bind(user, "男", "排球")(); // hico年龄18 性别:男 兴趣爱好排球
obj.objFn.bind(user, ["男", "乒乓球"])(null); // hico年龄18 性别:男 乒乓球 兴趣爱好null
不同的是:使用 bind 要调用它。
实现 call 函数
- call 是可以被所有方法调用的,毫无疑问的定义在 Funtion.prototype 上。
- 绑定函数被调用时,只传入第二个参数及之后的参数。
- 如果调用的函数被一个对象所拥有。那么该函数在调用时,内部 this 指向该对象。
Function.prototype.MyCall = function(ctx){
if(typeof this !== 'function'){
throw new TypeError('error');
}
ctx = ctx || window; // this 指向
const fn = Symbol('fn'); // 唯一
ctx[fn] = this; // 对象指向该函数
const arg = [...arguments].slice(1); // 获取实参
const rs = arguments.length > 1 ? ctx[fn](...arg) : ctx[fn]();
delete ctx[fn];
return rs;
};
let obj = {
name: "小东",
age: 20,
handler(a, b){
console.log(`名字:${this.name},年龄:${this.age},性别:${a},兴趣爱好:${b}`);
}
};
let user = {
name: '小明',
age: 18
}
obj.handler.MyCall(user, '男', '篮球'); // 名字:小明,年龄:18,性别:男,兴趣爱好:篮球
实现 apply 函数
- 实现 apply 方法和 call 差不多,我们只需要对参数进行不同处理就行了。
Function.prototype.MyApply = function(ctx){
if(typeof this !== 'function'){
throw new TypeError('error');
};
const fn = Symbol('fn'); // 唯一
ctx = ctx || window; // this 指向
ctx[fn] = this; // 绑定内部函数的 this
const rs = ctx[fn](...args); // 执行函数
delete ctx[fn];
return rs;
}
let obj = {
name: "小东",
age: 20,
handler(a, b){
console.log(`名字:${this.name},年龄:${this.age},性别:${a},兴趣爱好:${b}`);
}
};
let user = {
name: '小明',
age: 18
}
obj.handler.MyApply(user, ['男', '篮球']); // 名字:小明,年龄:18,性别:男,兴趣爱好:篮球
实现 bind 函数
- 与 apply 和 call 不一样是,bind 要调用了才会执行,不调用只是绑定 this 指向。
Function.prototype.MyBind = function (ctx) {
if(typeof this !== 'function'){
throw new TypeError('error');
};
const newCtx = JSON.parse(JSON.stringify(ctx)) || window; // 防止污染
const fn = Symbol('fn');
newCtx[fn] = this;
const args = [...arguments].slice(1); // 获取实参
// 返回一个绑定函数,等待调用
return function () {
const allArgs = args.concat([...arguments]); // 合并实参
// 以对象调用的形式调用 fn ,此时的 this 指向 ctx,也就是传入的需要绑定 this 指向
return allArgs.length ? newCtx[fn](...allArgs) : newCtx[fn]();
};
};
let obj = {
name: "小东",
age: 20,
handler(a, b) {
console.log(`名字:${this.name},年龄:${this.age},性别:${a},兴趣爱好:${b}`);
}
};
let user = {
name: '小明',
age: 18
};
obj.handler.bind(user, '男', '篮球')(null); // 名字:小明,年龄:18,性别:男,兴趣爱好:篮球
obj.handler.MyBind(user, '男', '篮球')(null); // 名字:小明,年龄:18,性别:男,兴趣爱好:篮球
obj.handler.MyBind(user, '女', '舞蹈')(null); // 名字:小明,年龄:18,性别:女,兴趣爱好:舞蹈
网友评论