菜单

this和call、apply、bind、argument

2019年4月1日 - 金沙前端

JavaScript 深入之call和apply的里丑捧心完结

2017/05/25 · JavaScript
· apply,
call

原稿出处: 冴羽   

由此call和apply的上行下效完结,带你爆料call和apply改变this的真相

JavaScript 深切之bind的一成不变达成

2017/05/26 · JavaScript
· bind

原来的小说出处: 冴羽   

return n + arguments.callee(n-1);  

依傍完毕第一步

模仿代码已经实现 百分之八十,还有三个小点要留心:

壹.this 参数能够传 null,当为 null 的时候,视为指向 window

举个例子:

var value = 1; function bar() { console.log(this.value); }
bar.call(null); // 1

1
2
3
4
5
6
7
var value = 1;
 
function bar() {
    console.log(this.value);
}
 
bar.call(null); // 1

固然那么些事例自己不采纳 call,结果还是一样。

二.函数是足以有再次回到值的!

举个例证:

var obj = { value: 1 } function bar(name, age) { return { value:
this.value, name: name, age: age } } console.log(bar.call(obj, ‘kevin’,
18)); // Object { // value: 1, // name: ‘kevin’, // age: 18 // }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var obj = {
    value: 1
}
 
function bar(name, age) {
    return {
        value: this.value,
        name: name,
        age: age
    }
}
 
console.log(bar.call(obj, ‘kevin’, 18));
// Object {
//    value: 1,
//    name: ‘kevin’,
//    age: 18
// }

只是都很好化解,让我们直接看第3版也便是终极一版的代码:

// 第三版 Function.prototype.call2 = 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; } // 测试一下 var value = 二; var obj = { value: 一 }
function bar(name, age) { console.log(this.value); return { value:
this.value, name: name, age: age } } bar.call(null); // 二console.log(bar.call二(obj, ‘kevin’, 18)); // 壹 // Object { // value: 一,
// name: ‘kevin’, // age: 18 // }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 第三版
Function.prototype.call2 = 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;
}
 
// 测试一下
var value = 2;
 
var obj = {
    value: 1
}
 
function bar(name, age) {
    console.log(this.value);
    return {
        value: this.value,
        name: name,
        age: age
    }
}
 
bar.call(null); // 2
 
console.log(bar.call2(obj, ‘kevin’, 18));
// 1
// Object {
//    value: 1,
//    name: ‘kevin’,
//    age: 18
// }

到此,我们做到了 call 的效仿达成,给本身二个赞 b( ̄▽ ̄)d

或者有人想到用 ES陆 的不二等秘书籍,不过 call 是 ES3 的格局,我们为了模仿完成3个ES三 的方法,要用到ES陆的法子,好像……,嗯,也足以啦。但是我们本次用 eval
方法拼成二个函数,类似于如此:
eval(‘context.fn(‘ + args +’)’)

深切种类

JavaScript深刻体系目录地址:。

JavaScript深切种类估摸写十五篇左右,意在帮大家捋顺JavaScript底层知识,重点教学如原型、成效域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等困难概念。

一经有荒唐或然不翼翼小心的地点,请务必给予指正,十二分感激。如若喜欢依旧持有启发,欢迎star,对小编也是1种鞭策。

本系列:

  1. JavaScirpt 深切之从原型到原型链
  2. JavaScript
    深切之词法作用域和动态成效域
  3. JavaScript 深切之推行上下文栈
  4. JavaScript 深刻之变量对象
  5. JavaScript 深切之功用域链
  6. JavaScript 深刻之从 ECMAScript 规范解读
    this
  7. JavaScript 深刻之实践上下文
  8. JavaScript 深刻之闭包
  9. JavaScript 深切之参数按值传递
  10. JavaScript
    深入之call和apply的依样葫芦达成

    1 赞 收藏
    评论

图片 1

                console.log(this.firstName + this.lastName);

效仿达成率先步

那正是说大家该怎么模拟达成那多少个成效呢?

试想当调用 call 的时候,把 foo 对象改造成如下:

var foo = { value: 1, bar: function() { console.log(this.value) } };
foo.bar(); // 1

1
2
3
4
5
6
7
8
var foo = {
    value: 1,
    bar: function() {
        console.log(this.value)
    }
};
 
foo.bar(); // 1

其一时候 this 就针对了 foo,是或不是很简短吗?

唯独这么却给 foo 对象自小编添加了叁个天性,那可那些啊!

然而也不用担心,大家用 delete 再删除它不就好了~

之所以我们模拟的手续能够分成:

  1. 将函数设为对象的属性
  2. 履行该函数
  3. 剔除该函数

上述个例子为例,正是:

// 第一步 foo.fn = bar // 第二步 foo.fn() // 第三步 delete foo.fn

1
2
3
4
5
6
// 第一步
foo.fn = bar
// 第二步
foo.fn()
// 第三步
delete foo.fn

fn 是指标的属性名,反正最后也要去除它,所以起成怎么样都不在乎。

依据这些思路,我们得以尝试着去写第一版的 call2 函数:

// 第二版 Function.prototype.call二 = function(context) { //
首先要博取调用call的函数,用this能够赢得 context.fn = this;
context.fn(); delete context.fn; } // 测试一下 var foo = { value: 一 };
function bar() { console.log(this.value); } bar.call二(foo); // 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 第一版
Function.prototype.call2 = function(context) {
    // 首先要获取调用call的函数,用this可以获取
    context.fn = this;
    context.fn();
    delete context.fn;
}
 
// 测试一下
var foo = {
    value: 1
};
 
function bar() {
    console.log(this.value);
}
 
bar.call2(foo); // 1

刚巧能够打印 一 哎!是或不是很满面红光!(~ ̄▽ ̄)~

如上个例证为例,便是:
// 第一步foo.fn = bar// 第二步foo.fn()// 第三步delete foo.fn

回来函数的一步一趋达成

从第二本性状开首,我们举个例子:

var foo = { value: 1 }; function bar() { console.log(this.value); } //
再次回到了一个函数 var bindFoo = bar.bind(foo); bindFoo(); // 一

1
2
3
4
5
6
7
8
9
10
11
12
var foo = {
    value: 1
};
 
function bar() {
    console.log(this.value);
}
 
// 返回了一个函数
var bindFoo = bar.bind(foo);
 
bindFoo(); // 1

有关钦命 this 的针对性,咱们能够利用 call 只怕 apply 达成,关于 call 和
apply
的萧规曹随完结,能够查阅《JavaScript深切之call和apply的一步一趋达成》。大家来写第一版的代码:

// 第一版 Function.prototype.bind2 = function (context) { var self =
this; return function () { self.apply(context); } }

1
2
3
4
5
6
7
8
// 第一版
Function.prototype.bind2 = function (context) {
    var self = this;
    return function () {
        self.apply(context);
    }
 
}

        console.log(this.user);//追梦子    

首要参考

新浪难点 不能够选用call、apply、bind,如何用 js 完结 call 恐怕 apply
的法力?

注意两点:
call 改变了 this 的指向,指向到 foo
bar 函数执行了

传参的如法泡制达成

接下去看第1点,能够流传参数。那个就有点令人费解了,笔者在 bind
的时候,是还是不是足以传参呢?笔者在推行 bind
再次回到的函数的时候,好还是不好传参呢?让大家看个例证:

var foo = { value: 1 }; function bar(name, age) {
console.log(this.value); console.log(name); console.log(age); } var
bindFoo = bar.bind(foo, ‘daisy’); bindFoo(’18’); // 1 // daisy // 18

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var foo = {
    value: 1
};
 
function bar(name, age) {
    console.log(this.value);
    console.log(name);
    console.log(age);
 
}
 
var bindFoo = bar.bind(foo, ‘daisy’);
bindFoo(’18’);
// 1
// daisy
// 18

函数须要传 name 和 age 四个参数,竟然还是能够在 bind 的时候,只传1个name,在履行回来的函数的时候,再传另多个参数 age!

那可怎么做?不急,大家用 arguments 进行处理:

// 第三版 Function.prototype.bind2 = function (context) { var self =
this; // 获取bind二函数从首个参数到终极2个参数 var args =
Array.prototype.slice.call(arguments, 一); return function () { //
那年的arguments是指bind重临的函数字传送入的参数 var bindArgs =
Array.prototype.slice.call(arguments); self.apply(context,
args.concat(bindArgs)); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 第二版
Function.prototype.bind2 = function (context) {
 
    var self = this;
    // 获取bind2函数从第二个参数到最后一个参数
    var args = Array.prototype.slice.call(arguments, 1);
 
    return function () {
        // 这个时候的arguments是指bind返回的函数传入的参数
        var bindArgs = Array.prototype.slice.call(arguments);
        self.apply(context, args.concat(bindArgs));
    }
 
}

    this.user = ‘追梦子’; 

apply的模仿达成

apply 的落到实处跟 call 类似,在此地一向给代码,代码来自于腾讯网 @郑航的完结:

Function.prototype.apply = 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; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Function.prototype.apply = 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;
}

fn 是指标的属性名,反正最终也要删减它,所以起成什么样都无所谓。
听新闻说这几个思路,大家得以尝尝着去写第壹版的 call2 函数:
// 第二版Function.prototype.call二 = function(context) { //
首先要获得调用call的函数,用this能够获得 context.fn = this;
context.fn(); delete context.fn;}// 测试一下var foo = { value:
一};function bar() { console.log(this.value);}bar.call②(foo); // 壹

四个小标题

接下去处理些符合规律:

1.apply 那段代码跟 MDN 上的稍有区别

在 MDN 中文版讲 bind 的效仿实现时,apply 这里的代码是:

self.apply(this instanceof self ? this : context || this,
args.concat(bindArgs))

1
self.apply(this instanceof self ? this : context || this, args.concat(bindArgs))

多了贰个关于 context 是不是留存的判断,可是那些是一无所能的!

举个例证:

var value = 2; var foo = { value: 1, bar: bar.bind(null) }; function
bar() { console.log(this.value); } foo.bar() // 2

1
2
3
4
5
6
7
8
9
10
11
var value = 2;
var foo = {
    value: 1,
    bar: bar.bind(null)
};
 
function bar() {
    console.log(this.value);
}
 
foo.bar() // 2

上述代码正常情状下会打字与印刷 2,假诺换来了 context || this,那段代码就会打字与印刷一!

于是那里不应该展开 context 的判定,我们查看 MDN
同样内容的英文版,就不存在这个判断!

二.调用 bind 的不是函数咋做?

拾1分,大家要报错!

if (typeof this !== “function”) { throw new
Error(“Function.prototype.bind – what is trying to be bound is not
callable”); }

1
2
3
if (typeof this !== "function") {
  throw new Error("Function.prototype.bind – what is trying to be bound is not callable");
}

三.自个儿要在线上用

那别忘了做个地位十分:

Function.prototype.bind = Function.prototype.bind || function () { …… };

1
2
3
Function.prototype.bind = Function.prototype.bind || function () {
    ……
};

本来最棒是用es5-shim啦。

1.2 var o = {

仿照达成第3步

最一开始也讲了,call 函数还是能够给定参数执行函数。举个例子:

var foo = { value: 1 }; function bar(name, age) { console.log(name)
console.log(age) console.log(this.value); } bar.call(foo, ‘kevin’, 18);
// kevin // 18 // 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var foo = {
    value: 1
};
 
function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}
 
bar.call(foo, ‘kevin’, 18);
// kevin
// 18
// 1

专注:传入的参数并不鲜明,那可如何是好?

不急,我们得以从 Arguments
对象中取值,取出第贰个到末了三个参数,然后嵌入3个数组里。

诸如那样:

// 以上个例证为例,此时的arguments为: // arguments = { // 0: foo, // 一:
‘kevin’, // 2: 1八, // length: 三 // } //
因为arguments是类数组对象,所以能够用for循环 var args = []; for(var i
= 1, len = arguments.length; i len; i++) { args.push(‘arguments[‘ + i +
‘]’); } // 执行后 args为 [foo, ‘kevin’, 18]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 以上个例子为例,此时的arguments为:
// arguments = {
//      0: foo,
//      1: ‘kevin’,
//      2: 18,
//      length: 3
// }
// 因为arguments是类数组对象,所以可以用for循环
var args = [];
for(var i = 1, len = arguments.length; i  len; i++) {
    args.push(‘arguments[‘ + i + ‘]’);
}
 
// 执行后 args为 [foo, ‘kevin’, 18]

不定长的参数难点一下子就解决了了,大家跟着要把这么些参数数组放到要履行的函数的参数里面去。

// 将数组里的成分作为两个参数放进函数的形参里 context.fn(args.join(‘,’))
// (O_o)?? // 那个格局肯定是尤其的哇!!!

1
2
3
4
// 将数组里的元素作为多个参数放进函数的形参里
context.fn(args.join(‘,’))
// (O_o)??
// 这个方法肯定是不行的啦!!!

兴许有人想到用 ES陆 的办法,不过 call 是 ES3 的点子,大家为了模仿完结一个ES3 的主意,要用到ES6的诀要,好像……,嗯,也足以啊。可是大家这一次用 eval
方法拼成三个函数,类似于如此:

eval(‘context.fn(‘ + args +’)’)

1
eval(‘context.fn(‘ + args +’)’)

此间 args 会自动调用 Array.toString() 那么些主意。

因此我们的第2版制服了五个大标题,代码如下:

// 第二版 Function.prototype.call2 = function(context) { context.fn =
this; var args = []; for(var i = 1, len = arguments.length; i len;
i++) { args.push(‘arguments[‘ + i + ‘]’); } eval(‘context.fn(‘ + args
+’)’); delete context.fn; } // 测试一下 var foo = { value: 一 }; function
bar(name, age) { console.log(name) console.log(age)
console.log(this.value); } bar.call二(foo, ‘kevin’, 1八); // kevin // 18
// 一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 第二版
Function.prototype.call2 = function(context) {
    context.fn = this;
    var args = [];
    for(var i = 1, len = arguments.length; i  len; i++) {
        args.push(‘arguments[‘ + i + ‘]’);
    }
    eval(‘context.fn(‘ + args +’)’);
    delete context.fn;
}
 
// 测试一下
var foo = {
    value: 1
};
 
function bar(name, age) {
    console.log(name)
    console.log(age)
    console.log(this.value);
}
 
bar.call2(foo, ‘kevin’, 18);
// kevin
// 18
// 1

(๑•̀ㅂ•́)و✧

模仿完毕率先步
那么我们该怎么模拟实现那多少个功用啊?
试想当调用 call 的时候,把 foo 对象改造成如下:
var foo = { value: 1, bar: function() { console.log(this.value)
}};foo.bar(); // 1

构造函数效果的模拟达成

完了了那两点,最难的片段到啊!因为 bind 还有1个表征,便是

1个绑定函数也能动用new操作符创建对象:那种行为就像是把原函数当成构造器。提供的
this 值被忽视,同时调用时的参数被提要求模拟函数。

约等于说当 bind 重临的函数作为构造函数的时候,bind 时钦命的 this
值会失效,但传播的参数依旧奏效。举个例子:

var value = 2; var foo = { value: 1 }; function bar(name, age) {
this.habit = ‘shopping’; console.log(this.value); console.log(name);
console.log(age); } bar.prototype.friend = ‘kevin’; var bindFoo =
bar.bind(foo, ‘daisy’); var obj = new bindFoo(’18’); // undefined //
daisy // 18 console.log(obj.habit); console.log(obj.friend); // shopping
// kevin

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var value = 2;
 
var foo = {
    value: 1
};
 
function bar(name, age) {
    this.habit = ‘shopping’;
    console.log(this.value);
    console.log(name);
    console.log(age);
}
 
bar.prototype.friend = ‘kevin’;
 
var bindFoo = bar.bind(foo, ‘daisy’);
 
var obj = new bindFoo(’18’);
// undefined
// daisy
// 18
console.log(obj.habit);
console.log(obj.friend);
// shopping
// kevin

小心:尽管在全局和 foo 中都注明了 value 值,最后还是再次回到了
undefind,表达绑定的 this 失效了,要是大家探听 new
的模拟实现,就会精通那一年的 this 已经指向了 obj。

(哈哈,作者那是为自个儿的下一篇小说《JavaScript长远类别之new的效仿完结》打广告)。

于是大家能够通过修改重临的函数的原型来贯彻,让我们写一下:

// 第3版 Function.prototype.bind二 = function (context) { var self =
this; var args = Array.prototype.slice.call(arguments, 一); var fbound =
function () { var bindArgs = Array.prototype.slice.call(arguments); //
当作为构造函数时,this 指向实例,self 指向绑定函数,因为下边一句
`fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为
绑定函数的 prototype,此时结果为 true,当结果为 true 的时候,this
指向实例。 // 当作为一般函数时,this 指向 window,self
指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的
context。 self.apply(this instanceof self ? this : context,
args.concat(bindArgs)); } // 修改重返函数的 prototype 为绑定函数的
prototype,实例就足以一而再函数的原型中的值 fbound.prototype =
this.prototype; return fbound; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 第三版
Function.prototype.bind2 = function (context) {
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
 
    var fbound = function () {
 
        var bindArgs = Array.prototype.slice.call(arguments);
        // 当作为构造函数时,this 指向实例,self 指向绑定函数,因为下面一句 `fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为 绑定函数的 prototype,此时结果为 true,当结果为 true 的时候,this 指向实例。
        // 当作为普通函数时,this 指向 window,self 指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的 context。
        self.apply(this instanceof self ? this : context, args.concat(bindArgs));
    }
    // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承函数的原型中的值
    fbound.prototype = this.prototype;
    return fbound;
}

尽管对原型链稍有困惑,能够查阅《JavaScript深刻之从原型到原型链》。

1.1 function a(){

深刻类别

JavaScript深远体系目录地址:。

JavaScript深切连串预计写拾5篇左右,意在帮大家捋顺JavaScript底层知识,重点讲解如原型、功能域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等困难概念。

假若有荒唐或然非常大心的地点,请务必给予指正,十三分感激。假如喜欢或许持有启发,欢迎star,对笔者也是1种鞭策。

本系列:

  1. JavaScirpt 深切之从原型到原型链
  2. JavaScript
    深远之词法作用域和动态功能域
  3. JavaScript 深切之推行上下文栈
  4. JavaScript 深切之变量对象
  5. JavaScript 长远之功能域链
  6. JavaScript 浓厚之从 ECMAScript 规范解读
    this
  7. JavaScript 深切之推行上下文
  8. JavaScript 深刻之闭包
  9. JavaScript 深切之参数按值传递

    1 赞 收藏
    评论

图片 2

浓密类别
JavaScript深远类别目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript深刻类别推断写十5篇左右,旨在帮大家捋顺JavaScript底层知识,重点教学如原型、成效域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等困难概念。
倘诺有错误或然一点都不小心的位置,请务必给予指正,十分谢谢。假使喜欢还是有所启发,欢迎star,对小编也是一种鞭策。

bind

一句话介绍 bind:

bind() 方法会创设贰个新函数。当以此新函数被调用时,bind()
的第一个参数将作为它运行时的
this,之后的壹体系参数将会在传递的实参前流传作为它的参数。(来自于 MDN
)

因而大家得以率先得出 bind 函数的两特性情:

  1. 回到3个函数
  2. 能够流传参数

var a =new fn; 

call

一句话介绍 call:

call() 方法在使用三个点名的 this
值和几何个钦赐的参数值的前提下调用有个别函数或艺术。

举个例子:

var foo = { value: 1 }; function bar() { console.log(this.value); }
bar.call(foo); // 1

1
2
3
4
5
6
7
8
9
var foo = {
    value: 1
};
 
function bar() {
    console.log(this.value);
}
 
bar.call(foo); // 1

瞩目两点:

  1. call 改变了 this 的指向,指向到 foo
  2. bar 函数执行了

此间 args 会自动调用 Array.toString() 那些法子。
因此大家的第3版征服了多少个大标题,代码如下:
// 第二版Function.prototype.call2 = function(context) { context.fn =
this; var args = []; for(var i = 1, len = arguments.length; i <
len; i++) { args.push(‘arguments[‘ + i + ‘]’); } eval(‘context.fn(‘ +
args +’)’); delete context.fn;}// 测试一下var foo = { value: 一};function
bar(name, age) { console.log(name) console.log(age)
console.log(this.value);}bar.call贰(foo, ‘kevin’, 1八); // kevin// 18// 一

构造函数效果的优化完毕

不过在那么些写法中,我们直接将 fbound.prototype =
this.prototype,我们一贯改动 fbound.prototype 的时候,也会平昔修改函数的
prototype。这年,大家可以经过多少个空函数来拓展转发:

// 第四版 Function.prototype.bind2 = function (context) { var self =
this; var args = Array.prototype.slice.call(arguments, 1); var fNOP =
function () {}; var fbound = function () { var bindArgs =
Array.prototype.slice.call(arguments); self.apply(this instanceof self ?
this : context, args.concat(bindArgs)); } fNOP.prototype =
this.prototype; fbound.prototype = new fNOP(); return fbound; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 第四版
Function.prototype.bind2 = function (context) {
 
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
 
    var fNOP = function () {};
 
    var fbound = function () {
        var bindArgs = Array.prototype.slice.call(arguments);
        self.apply(this instanceof self ? this : context, args.concat(bindArgs));
    }
    fNOP.prototype = this.prototype;
    fbound.prototype = new fNOP();
    return fbound;
 
}

到此截至,大的题材都曾经缓解,给本身二个赞!o( ̄▽ ̄)d

        getMessage.call(myObject,”未知”,22); //myObject 性别: 未知 age:
22       

小心:传入的参数并不鲜明,那可如何做?
不急,大家得以从 Arguments
对象中取值,取出第三个到结尾2个参数,然后嵌入一个数组里。
譬如说那样:
// 以上个例子为例,此时的arguments为:// arguments = {// 0: foo,// 一:
‘kevin’,// 2: 1八,// length: 3// }//
因为arguments是类数组对象,所以能够用for循环var args = [];for(var i =
1, len = arguments.length; i < len; i++) { args.push(‘arguments[‘ +
i + ‘]’);}// 执行后 args为 [foo, ‘kevin’, 18]

最后代码

为此最末尾的代码便是:

Function.prototype.bind2 = function (context) { if (typeof this !==
“function”) { throw new Error(“Function.prototype.bind – what is trying
to be bound is not callable”); } var self = this; var args =
Array.prototype.slice.call(arguments, 1); var fNOP = function () {}; var
fbound = function () { self.apply(this instanceof self ? this : context,
args.concat(Array.prototype.slice.call(arguments))); } fNOP.prototype =
this.prototype; fbound.prototype = new fNOP(); return fbound; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Function.prototype.bind2 = function (context) {
 
    if (typeof this !== "function") {
      throw new Error("Function.prototype.bind – what is trying to be bound is not callable");
    }
 
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
    var fNOP = function () {};
 
    var fbound = function () {
        self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
    }
 
    fNOP.prototype = this.prototype;
    fbound.prototype = new fNOP();
 
    return fbound;
 
}

}

到此,大家做到了 call 的模仿达成,给协调3个赞 b( ̄▽ ̄)d
apply的模拟达成
apply 的达成跟 call 类似,在那边平昔给代码,代码来自于搜狐@郑航的贯彻:
Function.prototype.apply = 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;}

var newFunc = obj一.bind(obj2,2,3)
bind发生了二个新的函数newFunc,其this指向为obj二

不定长的参数难点一举成功了,我们跟着要把这几个参数数组放到要履行的函数的参数里面去。
//
将数组里的因素作为三个参数放进函数的形参里context.fn(args.join(‘,’))//
(O_o)??// 那一个艺术自然是可怜的呐!!!

壹.非构造函数版this

正要能够打印 一 哎!是还是不是很开心!(~ ̄▽ ̄)~
依样葫芦完结第三步
最一伊始也讲了,call 函数还是可以给定参数执行函数。举个例子:
var foo = { value: 1};function bar(name, age) { console.log(name)
console.log(age) console.log(this.value);}bar.call(foo, ‘kevin’, 18);//
kevin// 18// 1

function add(c,d){ 

举个例证:
var foo = { value: 1};function bar() {
console.log(this.value);}bar.call(foo); // 1

        a:12,

call
一句话介绍 call:
call() 方法在使用三个点名的 this
值和多少个钦赐的参数值的前提下调用某些函数或措施。

console.log(add.call(s,3,4)); // 1+2+3+4 = 10    

然而都很好化解,让我们一贯看第二版也正是最终1版的代码:
// 第三版Function.prototype.call2 = 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;}// 测试一下var value = 二;var obj = { value: 一}function
bar(name, age) { console.log(this.value); return { value: this.value,
name: name, age: age }}bar.call(null); // 二console.log(bar.call二(obj,
‘kevin’, 1捌));// 1// Object {// value: 一,// name: ‘kevin’,// age: 18// }

二.大家得以借用arguments.callee来让匿名函数完成递归:

(๑•̀ㅂ•́)و✧
仿照完毕第贰步
依傍代码已经形成 百分之八十,还有三个小点要留意:
1.this 参数能够传 null,当为 null 的时候,视为指向 window
举个例子:
var value = 1;function bar() { console.log(this.value);}bar.call(null);
// 1

        window.lastName = “_xie”;

即使如此那一个事例本人不使用 call,结果仍旧壹样。
二.函数是足以有重返值的!
举个例子:
var obj = { value: 1}function bar(name, age) { return { value:
this.value, name: name, age: age }}console.log(bar.call(obj, ‘kevin’,
18));// Object {// value: 1,// name: ‘kevin’,// age: 18// }

1.3  var o = {

以此时候 this 就针对了 foo,是否很简短吗?
不过这么却给 foo 对象自笔者添加了2特质量,那可不行呀!
只是也不用担心,我们用 delete 再删除它不就好了~
因而我们模拟的步调能够分为:
将函数设为对象的天性
推行该函数
删除该函数

4.Bind

    user:”追梦子”,

console.log(a.user); //undefined
 由于重回了二个指标所以this指向再次来到的靶子而不是a对象

        getName.apply(myObject);// myObject        

}

j(); //此时this指向window

    var user =”追梦子”;

    console.log(“func arg len”,funcLen);

        getMessage.call(window,”女”,21); //Cynthia_xie 性别: 女 age:
21        

a();相当于window.a()所以a指向window

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图