博客
关于我
简单模拟实现javascript中的call、apply、bind方法
阅读量:432 次
发布时间:2019-03-06

本文共 2699 字,大约阅读时间需要 8 分钟。

模拟实现JavaScript中的call、apply、bind方法

隐式丢失问题

在JavaScript中,函数的this指针在某些情况下会经历隐式丢失。这种现象通常发生在以下场景:

场景1:引用传递

var a = 'window';
function foo() {
console.log(this.a);
}
var obj = {
a: 'obj',
foo: foo
};
obj.foo(); // 输出: 'obj',此时`this`指向`obj`
var lose = obj.foo; // lose() 的`this`指向`window`
lose(); // 输出: 'window'

场景2:作为回调函数传入

var a = 'window';
function foo() {
console.log(this.a);
}
var obj = {
a: 'obj',
foo: foo
};
function lose(callback) {
callback();
}
lose(obj.foo); // 输出: 'window',此时`this`指向`window`

总结

无论函数如何被传递,只要它没有被显式绑定,最后一次调用都会应用默认绑定规则。因此,在处理隐式丢失问题时,我们需要找到一种方法,确保函数在被调用时this指向正确的上下文。

硬绑定

硬绑定是一种解决隐式丢失问题的方法。它允许我们在函数被定义时,明确指定其this指针的上下文。这种绑定方式一旦建立后,无论函数如何被调用,其this指针都不会改变。

示例

var a = 'window';
function foo() {
console.log(this.a);
}
var obj = {
a: 'obj',
foo: foo
};
lose(obj.foo); // 输出: 'window',此时`this`指向`window`
// 通过硬绑定解决问题
var fixTheProblem = obj.foo.bind(obj);
lose(fixTheProblem); // 输出: 'obj',此时`this`指向`obj`

模拟实现原理分析

模拟实现call方法

Function.prototype._call = function($this, ...parms) {
var funcCaller = this;
$this['caller'] = funcCaller;
$this['caller'](...parms);
delete $this['caller'];
};

模拟实现apply方法

Function.prototype._apply = function($this, parmsArr) {
var funcCaller = this;
$this['caller'] = funcCaller;
$this['caller'](...parmsArr);
delete $this['caller'];
};

模拟实现bind方法

Function.prototype._bind = function($this, ...parms) {
var bindCaller = this;
return function() {
return bindCaller._apply($this, parms);
};
};

总体实现

function interface4CallAndApply(caller, $this, parmsOrParmArr) {
$this['caller'] = caller;
$this['caller'](...parmsOrParmArr);
delete $this['caller'];
}
Function.prototype._call = function($this, ...parms) {
var funcCaller = this;
interface4CallAndApply(funcCaller, $this, parms);
};
Function.prototype._apply = function($this, parmsArr) {
var funcCaller = this;
interface4CallAndApply(funcCaller, $this, parmsArr);
};
Function.prototype._bind = function($this, ...parms) {
var bindCaller = this;
return function() {
return bindCaller._apply($this, parms);
};
};

测试

var foo = {
name: 'foo',
sayHello: function(a, b) {
console.log(`hello, get the parms: ${a} and ${b}`);
}
};
var bar = {
name: 'bar'
};
foo.sayHello._call(bar, 'Fitz', 'smart');
foo.sayHello._apply(bar, ['Fitz', 'smart']);
var baz = foo.sayHello._bind(bar, 'Fitz', 'smart');
baz();
// 测试硬绑定的应用
var testHardBind = foo.sayHello._bind(bar, 'hard', 'bind');
testHardBind._call(Object.create(null));
// 输出: 'hello, get the parms: hard and bind'

本文通过模拟实现JavaScript中的callapplybind方法,探讨了隐式丢失问题以及硬绑定解决方案的原理。通过实际代码示例,验证了不同方法在不同场景下的表现。

转载地址:http://mcnuz.baihongyu.com/

你可能感兴趣的文章
OA系统选型:选择好的工作流引擎
查看>>
OA让企业业务流程管理科学有“据”
查看>>
OA项目之会议通知(查询&是否参会&反馈详情)
查看>>
Vue.js 学习总结(13)—— Vue3 version 计数介绍
查看>>
OA项目之我的会议(会议排座&送审)
查看>>
OA项目之我的会议(查询)
查看>>
OA项目之我的审批(会议查询&会议签字)
查看>>
OA项目之项目简介&会议发布
查看>>
ObjC的复制操作
查看>>
Object c将一个double值转换为时间格式
查看>>
object detection之Win10配置
查看>>
object detection训练自己数据
查看>>
object detection错误Message type "object_detection.protos.SsdFeatureExtractor" has no field named "bat
查看>>
object detection错误之Could not create cudnn handle: CUDNN_STATUS_INTERNAL_ERROR
查看>>
object detection错误之no module named nets
查看>>
Object of type 'ndarray' is not JSON serializable
查看>>
Object Oriented Programming in JavaScript
查看>>
object references an unsaved transient instance - save the transient instance before flushing
查看>>
Object 类的常见方法有哪些?
查看>>
Object-c动态特性
查看>>