实际上this的最终指向的是那个调用它的对象,由

作者: 前端  发布:2019-09-26

仿照达成第二步

最一初叶也讲了,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 对象中取值,抽取第叁个到尾数参数,然后嵌入三个数组里。

举个例子那样:

// 以上个例子为例,此时的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]

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)??
// 这个方法肯定是不行的啦!!!

或者有人想到用 ES6 的点子,然则 call 是 ES3 的主意,大家为了参谋完毕多个ES3 的秘诀,要用到ES6的秘诀,好像……,嗯,也能够啦。不过大家此次用 eval 方法拼成二个函数,类似于那般:

eval('context.fn(' + args +')')

1
eval('context.fn(' + args +')')

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

由此我们的第二版战胜了多少个大主题素材,代码如下:

// 第二版 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

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

(๑•̀ㅂ•́)و✧

正巧能够打字与印刷 1 哎!是否很欢悦!(~ ̄▽ ̄)~
仿照达成第二步
最一最早也讲了,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.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;
 
}

3.1 apply(obj,[argArray]), call(obj,arg1,arg2,arg3...)

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 函数实行了

深深体系
JavaScript深刻连串目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript深刻体系猜测写十五篇左右,目的在于帮咱们捋顺JavaScript底层知识,入眼讲明如原型、功用域、实施上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、承袭等难题概念。
一旦有错误可能不严格的地点,请必须给予指正,十三分谢谢。如果喜欢只怕有所启发,应接star,对小编也是一种鞭笞。

构造函数效果的优化实现

而是在那几个写法中,大家直接将 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

    console.log("really arg len",reallyLen);

效仿实现率先步

这正是说大家该怎么模拟完毕这多少个职能啊?

试想当调用 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.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

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

碰巧能够打字与印刷 1 哎!是或不是很欢悦!(~ ̄▽ ̄)~

可能有人想到用 ES6 的点子,可是 call 是 ES3 的点子,咱们为了参照他事他说加以考察实现叁个ES3 的主意,要用到ES6的秘技,好像……,嗯,也足以啦。可是大家这一次用 eval 方法拼成一个函数,类似于如此:
eval('context.fn(' + args +')')

JavaScript 深远之bind的一成不改变达成

2017/05/26 · JavaScript · bind

初稿出处: 冴羽   

    a:10,

深刻连串

JavaScript深刻连串目录地址:。

JavaScript深刻种类猜测写十五篇左右,意在帮我们捋顺JavaScript底层知识,入眼讲明如原型、成效域、试行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难题概念。

假定有错误也许不稳重的地方,请必需给予指正,非常多谢。假使喜欢恐怕有所启发,应接star,对笔者也是一种鞭笞。

本系列:

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

    1 赞 收藏 评论

图片 1

留意:传入的参数并不分明,那可如何做?
不急,大家得以从 Arguments 对象中取值,收取第二个到最后一个参数,然后放到一个数组里。
诸如这样:
// 以上个例子为例,此时的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]

构造函数效果的效仿达成

成就了这两点,最难的片段到啊!因为 bind 还只怕有三个特色,正是

叁个绑定函数也能应用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的模拟实现》打广告)。

所以大家能够经过退换重回的函数的原型来兑现,让大家写一下:

// 第三版 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; }

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浓厚之从原型到原型链》。

5.argument

根本参谋

腾讯网难题 不能够利用call、apply、bind,怎么样用 js 实现 call 可能 apply 的效应?

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

多少个小题目

接下去管理些没非常:

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,这段代码就能够打字与印刷1!

就此那边不应有进行 context 的剖断,大家查看 MDN 一样内容的匈牙利语版,就不设有那一个论断!

2.调用 bind 的不是函数咋办?

非常,大家要报错!

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");
}

3.自家要在线上用

那别忘了做个非凡:

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

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

本来最佳是用es5-shim啦。

this:this的对准在函数定义的时候是规定不了的,独有函数实行的时候技术确定this到底指向何人,实际上this的最终指向的是十三分调用它的目的

JavaScript 深远之call和apply的模仿达成

2017/05/25 · JavaScript · apply, call

原著出处: 冴羽   

不定长的参数难点化解了,我们跟着要把那几个参数数组放到要实行的函数的参数里面去。
// 将数组里的要素作为多少个参数放进函数的形参里context.fn(args.join(','))// (O_o)??// 这些措施分明是极度的哇!!!

bind

一句话介绍 bind:

bind() 方法会创制叁个新函数。当以此新函数被调用时,bind() 的率先个参数将作为它运转时的 this,之后的一体系参数将会在传递的实参前传出作为它的参数。(来自于 MDN )

由此大家得以率先得出 bind 函数的三个特点:

  1. 回去一个函数
  2. 能够流传参数

        var myObject = {firstName:'my', lastName:'Object'};

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;
}

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

深远体系

JavaScript深切体系目录地址:。

JavaScript深刻种类估计写十五篇左右,目的在于帮大家捋顺JavaScript底层知识,入眼教学如原型、功效域、试行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、承接等困难概念。

若是有荒唐只怕不严谨的地方,请必须给予指正,十三分谢谢。假若喜欢依旧持有启发,接待star,对作者也是一种鞭笞。

本系列:

  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 赞 收藏 评论

图片 2

2.构造函数版this

效仿实现第三步

依傍代码已经产生 十分九,还应该有五个小点要注意:

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,结果依然同样。

2.函数是足以有再次来到值的!

举个例证:

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
// }

只是都很好消除,让大家直接看第三版也便是最后一版的代码:

// 第三版 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 // }

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

举个例子:
var foo = { value: 1};function bar() { console.log(this.value);}bar.call(foo); // 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 的时候,只传叁个name,在实施回来的函数的时候,再传另一个参数 age!

那可如何做?不急,大家用 arguments 举行管理:

// 第二版 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)); } }

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));
    }
 
}

        getName.call(window); // Cynthia_xie       

小心两点:
call 改变了 this 的指向,指向到 foo
bar 函数试行了

重返函数的萧规曹随完毕

从第贰本本性早先,大家比如:

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

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);
    }
 
}

}

以上个例子为例,正是:
// 第一步foo.fn = bar// 第二步foo.fn()// 第三步delete foo.fn

console.log(a.user); //追梦子 this指向a对象

到此,我们达成了 call 的因循古板实现,给和谐叁个赞 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;}

            console.log(this.a);//undefinedconsole.log(this);//window        }

此间 args 会自动调用 Array.toString() 这几个法子。
进而大家的第二版克制了五个大标题,代码如下:
// 第二版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

var sum = function(n) {  

由此call和apply的东施东施效颦达成,带你爆料call和apply改换this的原形

    console.log(this);//Window

模仿完结率先步
那正是说大家该怎么模拟达成那四个职能呢?
试想当调用 call 的时候,把 foo 对象改形成如下:
var foo = { value: 1, bar: function() { console.log(this.value) }};foo.bar(); // 1

o.fn(); o调用fn,所以this指向o

fn 是指标的属性名,反正最后也要刨除它,所以起成什么样都不在乎。
据悉这么些思路,大家能够品尝着去写第一版的 call2 函数:
// 第一版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

    var reallyLen = arguments.length;

可是都很好消除,让大家一向看第三版也正是最终一版的代码:
// 第三版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); // 2console.log(bar.call2(obj, 'kevin', 18));// 1// Object {// value: 1,// name: 'kevin',// age: 18// }

var foo={

那一年 this 就针对了 foo,是否很简短吗?
唯独这么却给 foo 对象自己加多了叁本性质,那可丰盛呀!
然而也不用忧虑,大家用 delete 再删除它不就好了~
于是大家模拟的手续能够分为:
将函数设为对象的性格
推行该函数
删除该函数

    var funcLen = add.length;

就算如此那么些例子自身不利用 call,结果如故同样。
2.函数是能够有再次来到值的!
举个例子:
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// }

// [Log] func arg len – 2

        }

        fn:function(){

万一var func =  bar.bind(foo)改为:var func =  bar.bind(foo,2,3),那么输出为:3 2 3

    this.user = "追梦子";

分歧点:接收参数格局各异 

bar()

2.大家得以借用arguments.callee来让佚名函数完结递归:

    console.log("func arg len",funcLen);

  console.log(this.x,a,b); 

if(n == 1) {  

                console.log(this.firstName + this.lastName + " 性别: " + sex + " age: " + age );

2.1 function Fn(){

console.log(add.apply(s,[5,6])); // 1+2+5+6 = 14

var s = {a:1, b:2};

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

如:var bar=function(a,b){

        getName.apply(window); // Cynthia_xie        

}

}

function add(c,d){ 

}

         getName.call(myObject); // myObject        

        a:12,

}  

    x:3 

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

var a =new fn; 

}

1.1 function a(){

    this.user = '追梦子'; 

var func =  bar.bind(foo);

    console.log(this.user);//undefined

1.3  var o = {

console.log(a.user); //undefined  由于再次来到了贰个目的所以this指向再次来到的对象并不是a对象

add(1,2,3,4,5)

    var user ="追梦子";

        }

}

此时出口为:3 3 4

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

return 1;  

    b:{

1.非构造函数版this

 }  

func(3,4)

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

    this.user = '追梦子'; 

var a =new fn; 

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

        functiongetMessage(sex,age){            

console.log("sum =", sum(5)); 

1、我们得以借用arguments.length能够来查看实参和形参的个数是还是不是一律:

}

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

1.2 var o = {

        window.lastName = "_xie";

4.Bind

var a =new Fn();

}

     return this.a + this.b + c + d;

    }

// [Log] really arg len – 5

        functiongetName(){            

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

         getMessage.apply(myObject,["未知",22]); // myObject 性别: 未知 age: 22

}else {  

    return {}; //或者:return function(){};

var j = o.b.fn;

2.3 function fn()

        getMessage.apply(window,["女",21]); // Cynthia_xie 性别: 女 age: 21        

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

3.call和apply

function add(a,b){

同样点:退换函数内部的this指向

    return 1; //或者:return undefined;

    fn:function(){

    user:"追梦子",

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

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

            }

3.2  window.firstName = "Cynthia";

}

        getName.apply(myObject);// myObject        

2.2 function fn()

本文由9159.com发布于前端,转载请注明出处:实际上this的最终指向的是那个调用它的对象,由

关键词:

上一篇:英文翻译,英文翻译
下一篇:没有了