原生实现JavaScript的call()apply()bind()
Posted cwxblog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原生实现JavaScript的call()apply()bind()相关的知识,希望对你有一定的参考价值。
前言
call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向。
我们先来看一个例子
let obj =
name: "大卫"
function person()
console.log("name", this.name)
// 用原生apply调用
person.apply(obj) // name: 大卫
实现上,可以理解这样理解call, apply 的实现过程:
- 将函数添加到绑定对象的属性
- 执行该函数
- 删除该属性
let obj =
name: "大卫",
function person()
console.log("name", this.name)
obj.person(); // name: 大卫
具体实现如下
call
- call方法的第一个参数也是this的指向,后面传入的是一个参数列表
- call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
- call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。
es6实现
// 1. 保存this(当前函数)
// 2. 添加函数作为obj的属性
// 3. 执行该函数
// 4. 删除该属性(函数)
// 5. 返回函数执行结果
Function.prototype.call2 = function (obj, ...args)
obj = obj || window;
const symbol = Symbol("fn");
obj[symbol] = this;
const result = obj[symbol](...args);
delete obj[symbol];
return result;
;
// example
let obj =
name: "大卫"
;
function myName(age, height)
console.log(this.name);
console.log("年龄:", age);
console.log("身高:", height);
myName.call2(obj, 23, 172);
// 大卫
// 年龄: 23
// 身高: 172
es5实现
Function.prototype.call3 = function (context)
var context = context || window;
context.fn = this;
var args = [];
for (var i = 1, len = arguments.length; i < len; i++)
args.push("arguments[" + i + "]");
var result = eval("context.fn(" + args + ")");
delete context.fn;
return result;
;
// example
var value3 = 2;
var obj3 =
value3: 1
;
function bar3(name, age)
console.log(this.value3);
return
value: this.value3,
name: name,
age: age
;
bar3.call3(null); // 2 ,this执行为空时,默认为window对象
console.log(bar.call3(obj3, "kevin", 18));
// 1
//
// age: 18
// name: "kevin"
// value: 1
//
apply
- apply接受两个参数,第一个参数是this的指向对象,第二个参数是函数接受的参数,以数组的形式传入
es6实现
// 1. 保存this(当前函数)
// 2. 添加函数作为obj的属性
// 3. 执行该函数
// 4. 删除该属性(函数)
// 5. 返回函数执行结果
Function.prototype.apply2 = function(obj, args)
let obj = obj || window;
if (typeof this !== 'function')
throw new Error('Type Error')
const symbol = Symbol('fn');
obj[symbol] = this;
const res = obj[symbol](...args);
delete obj[symbol]
return res;
// example
let obj =
name: "大卫"
function myName(age, height)
console.log(this.name)
console.log("年龄:", age)
console.log("身高:", height)
myName.apply2(obj, [23,172])
es5实现
Function.prototype.apply3 = function (context, arr)
var context = Object(context) || window;
context.fn = this;
var result;
if (!arr)
result = context.fn();
else
var args = [];
for (var i = 0, len = arr.length; i < len; i++)
args.push("arr[" + i + "]");
result = eval("context.fn(" + args + ")");
delete context.fn;
return result;
;
bind
- bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)
- 改变this指向后不会立即执行,而是返回一个永久改变this指向的函数
- 由此我们可以首先得出 bind 函数的两个特点:
- 返回一个函数
- 可以传入参数
es6实现 利用apply
Function.prototype.bind2 = function (obj, ...args)
if (typeof this !== 'function')
throw new Error('Type error')
const self = this;
return function F()
// 考虑new的情况
if (this instanceof F)
return new self(...args, ...arguments)
return self.apply(obj, [...args, ...arguments])
;
;
// example
let obj =
name: "大卫"
function myName(age, height)
console.log(this.name)
console.log("年龄:", age)
console.log("身高:", height)
let newMyName = myName.bind2(obj, 22);
newMyName(172)
es5实现
Function.prototype.bind3 = function (obj)
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () ;
var fBound = function ()
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fNOP ? this : obj, args.concat(bindArgs));
;
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
;
参考链接:
JavaScript深入之call和apply的模拟实现
Function.prototype.call()
Function.prototype.apply()
Function.prototype.bind()
以上是关于原生实现JavaScript的call()apply()bind()的主要内容,如果未能解决你的问题,请参考以下文章
原生实现JavaScript的call()apply()bind()
原生实现JavaScript的call()apply()bind()