call、applay、bind是改变函数上下文this的常用方式,下面将对其使用及实现方式进行分析。
call
函数解析
call为Function.prototype.call,call方法的参数由一个制定的this和一个或多个参数来调用,需要注意的是call方法接受的参数是参数列表。MDN官方示例如下:
1 2 3 4 5 6 7 8 9 10 11
| function Product(name, price) { this.name = name; this.price = price; }
function Food(name, price) { Product.call(this, name, price); this.category = 'food'; }
console.log(new Food('cheese', 5).name);
|
函数实现
1 2 3 4 5 6 7 8
| Function.prototype.myCall = function(context) { context = context || window; context.fn = this; var args = [...arguments].slice(1) var result = context.fn(...args); delete context.fn; return result; }
|
- context为可选参数,传null则为windows
- 为context创建一个fn属性并指向this
- 因为call可以传多个参数进来,所以需要把参数剥离
apply
函数解析
Function.prototype.apply:apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
1 2 3 4 5 6 7 8 9
| var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers);
console.log(max);
var min = Math.min.apply(null, numbers);
console.log(min);
|
函数实现
1 2 3 4 5 6 7 8 9 10 11 12 13
| Function.prototype.myApply = function() { context = context || window; context.fn = this; var result = null; if (arguments[1]) { result = context.fn(...arguments[1]); } else { result = context.fn(); }
delete context.fn; return result; }
|
apply的实现和call的实现类似,唯一的区别在于对参数的处理上。
bind
函数解析
用Function.prototype.bind方法创建一个新的函数,在bind()被调用是,这个函数的this被bind的第一个参数指定。MDN实例代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var module = { x: 42, getX: function() { return this.x; } }
var unboundGetX = module.getX; console.log(unboundGetX());
var boundGetX = unboundGetX.bind(module); console.log(boundGetX());
|
函数实现
对于bind函数有两个特点,返回一个函数,可以传入参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Function.prototype.myBind = function(context) { var _ = this;
var args = Array.prototype.slice.call(arguments, 1); var fNop = function() {}; var fBound = function() { var bindArgs = Array.prototype.slice.call(arguments); _.apply(this instanceof _ ? this: context, args.concat(bindArgs)); }
fNop.prototype = this.prototype; fBound.prototype = new fNop(); return fBound; }
|