手写call、apply、bind函数
栏目: JavaScript · 发布时间: 6年前
-
特点:
- 1)可以改变我们当前函数的this指向
- 2)还会让当前函数执行
Function.prototype.call = function (context) {
if (typeof this !== 'function') {
throw new TypeError(`${this} is not a function`)
}
context = Object(context) || window;
context.fn = this;
let args = [];
for (let i = 1; i < arguments.length; i++) {
args.push('arguments['+i+']');
}
let r = eval('context.fn('+args+')');
delete context.fn;
return r;
}
复制代码
题目自测
function fn1() {
console.log(this,arguments);
console.log(1);
}
function fn2() {
console.log(this,arguments);
console.log(2);
}
fn1.call(fn2,1,2); // fn2 [1,2] 1
fn1.call.call.call.call.call(fn2,1,2); // {number:1} [2] 2
复制代码
-
思路解析
-
fn1.call(fn2,1,2)-
1)
call执行传入fn2,1,2三个参数 -
2)
call函数内部context = Object(fn2) = fn2 -
3)
fn2.fn = fn1 -
4)
args=['arguments[1]','arguments[2]']=[1,2] -
5)
eval('context.fn('+args+')') = fn2.fn(1,2) = fn2.fn1(1,2)
-
1)
-
fn1.call.call.call.call.call(fn2,1,2)-
1)
call执行传入fn2,1,2三个参数 -
2)
call函数内部context = Object(fn2) = fn2 -
3)
fn2.fn = call -
4)
args=['arguments[1]',arguments[2]]=[1,2] -
5)
eval('context.fn('+args+')') = fn2.fn(1,2) = fn2.call(1,2) -
6)
call执行传入1,2两个参数 -
7)
call函数内部context = Object(1) = Number{1} -
8)
Number{1}.fn = fn2 -
9)
args=['arguments[1]']=[1] -
10)
eval('context.fn('+args+')') = Number{1}.fn(2) = Number{1}.fn2(2) -
注:多次调用
call的时候其实是call执行的时候内部又调用了一次call,总共调用两次
-
1)
-
apply
函数
-
特点:
- 1)可以改变我们当前函数的this指向
- 2)还会让当前函数执行
Function.prototype.apply = function (context,args) {
if (typeof this !== 'function') {
throw new TypeError(`${this} is not a function`)
}
context = Object(context) || window;
context.fn = this;
if(!args){
return context.fn();
}
let r = eval('context.fn('+args+')');
delete context.fn;
return r;
}
复制代码
new
操作符
-
特点
this
/*
*基本使用
*/
function Animal(type) {
this.type = type ;
}
Animal.prototype.say = function () {
console.log('say');
}
let tiger = new Animal('tiger');
console.log(tiger);
--------------------------------------------------------
/*
*方法实现
*/
function mockNew(){
let Constructor = [].shift.call(arguments);
let obj = {}; // 新生成了对象
obj.__proto__ = Constructor.prototype; // 链接到原型
let r = Constructor.apply(obj,arguments) // 绑定`this`
return r instance Object ? r : obj; //返回一个对象
}
let tiger = mockNew(Animal,'tiger');
console.log(tiger);
复制代码
bind
函数
-
特点
-
绑定
this指向 - 返回一个绑定后的函数(高阶函数原理)
-
如果绑定的函数被
new执行 ,当前函数的this就是当前的实例 -
new出来的结果可以找到原有类的原型
-
绑定
Function.prototype.bind = function (context) {
if (typeof this !== 'function') {
throw new TypeError(`${this} is not a function`)
}
let that = this;
let bindArgs = Array.prototype.slice.call(arguments, 1);
function Fn() { };
function bindFn() {
let args = Array.prototype.slice.call(arguments);
/*
* 绑定`this`指向
* 如果绑定的函数被`new`执行 ,当前函数的`this`就是当前的实例
*/
that.apply(this instanceof bindFn ? this : context, bindArgs.concat(args));
}
/*`new`出来的结果可以找到原有类的原型*/
Fn.prototype = that.prototype;
bindFn.prototype = new Fn();
/*返回一个绑定后的函数*/
return bindFn;
}
复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Test Driven Development
Kent Beck / Addison-Wesley Professional / 2002-11-18 / USD 49.99
Quite simply, test-driven development is meant to eliminate fear in application development. While some fear is healthy (often viewed as a conscience that tells programmers to "be careful!"), the auth......一起来看看 《Test Driven Development》 这本书的介绍吧!