>

带你揭开call和apply改变this的真相sbf282.com,举个例

- 编辑:澳门博发娱乐官网 -

带你揭开call和apply改变this的真相sbf282.com,举个例

传送参数

将参数从叁个函数字传送递到另叁个函数

// 使用 apply 将 foo 的参数传递给 bar function foo() { bar.apply(this, arguments); } function bar(a, b, c) { console.log(a, b, c); } foo(1, 2, 3)

1
2
3
4
5
6
7
8
9
// 使用 apply 将 foo 的参数传递给 bar
function foo() {
    bar.apply(this, arguments);
}
function bar(a, b, c) {
   console.log(a, b, c);
}
 
foo(1, 2, 3)

深切连串

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

sbf282.com 1

深刻种类
JavaScript长远体系目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript深切种类估算写十五篇左右,目的在于帮大家捋顺JavaScript底层知识,爱慕解说如原型、功用域、推行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、承袭等难处概念。
要是有荒唐只怕十分的大心的地方,请必需给予指正,十一分多谢。假如喜欢仍旧有所启发,接待star,对作者也是一种鞭笞。

何以在浏览器中运作JavaScript?
  • <script> console.log('运行JS') </script>
  • <script src='./*'> </script>

回去函数的百无一成反类犬完毕

从第二个特征早先,大家举例:

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

调用数组方法

假定类数组正是轻松的想用数组的办法怎么做呢?

既然不也许直接调用,大家得以用 Function.call 直接调用:

var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 } Array.prototype.join.call(arrayLike, '&'); // name&age&sex Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"] // slice能够完毕类数组转数组 Array.prototype.map.call(arrayLike, function(item){ return item.toUpperCase(); }); // ["NAME", "AGE", "SEX"]

1
2
3
4
5
6
7
8
9
10
11
var arrayLike = {0: 'name', 1: 'age', 2: 'sex', length: 3 }
 
Array.prototype.join.call(arrayLike, '&'); // name&age&sex
 
Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"]
// slice可以做到类数组转数组
 
Array.prototype.map.call(arrayLike, function(item){
    return item.toUpperCase();
});
// ["NAME", "AGE", "SEX"]

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

2017/05/25 · JavaScript · apply, call

原稿出处: 冴羽   

不定长的参数难点一挥而就了,大家跟着要把这么些参数数组放到要执行的函数的参数里面去。
// 将数组里的因素作为七个参数放进函数的形参里context.fn(args.join(','))// (O_o)??// 那个措施自然是特别的啊!!!

注释
  • 单行:/那是注释/。
  • 多行:/*那是注释*/。

最终代码

所以最末尾的代码正是:

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

Arguments对象

接下去入眼讲讲 Arguments 对象。

Arguments 对象只定义在函数体中,富含了函数的参数和任何属性。在函数体中,arguments 指代该函数的 Arguments 对象。

举个例证:

function foo(name, age, sex) { console.log(arguments); } foo('name', 'age', 'sex')

1
2
3
4
5
function foo(name, age, sex) {
    console.log(arguments);
}
 
foo('name', 'age', 'sex')

打字与印刷结果如下:

sbf282.com 2

我们能够看看除了类数组的索引属性和length属性之外,还应该有贰个callee属性,接下去我们二个三个介绍。

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

效仿达成率先步
那么大家该怎么模拟达成那五个效果与利益啊?
试想当调用 call 的时候,把 foo 对象更改成如下:
var foo = { value: 1, bar: function() { console.log(this.value) }};foo.bar(); // 1

JavaScript之父:Brendan Eich 。

-基本语法:借鉴了C语言和Java语言。
-数据结构:借鉴了Java,满含将值分成原始值和对象两大类。

  • 函数的用法:借鉴了Scheme和Awk语言,将函数当成第一等人民,引进闭包。
  • 原型承接模型:借鉴了Self语言。
  • 正则表明式:借鉴了Perl语言。
  • 字符串和数组管理:借鉴了Python语言。

JavaScript 深入之bind的效仿实现

2017/05/26 · JavaScript · bind

原作出处: 冴羽   

应用

arguments的接纳其实过多,在下个密密麻麻,也正是 JavaScript 专项论题体系中,我们会在 jQuery 的 extend 达成、函数柯里化、递归等场景看见arguments 的身影。那篇文章就不现实进行了。

假设要总括那么些情形的话,权且能体会掌握的统揽:

  1. 参数不定长
  2. 函数柯里化
  3. 递归调用
  4. 函数重载

款待留言回复。

仿照完结第三步

依傍代码已经做到 十分九,还应该有两个小点要在意:

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

就算那些例子自身不选择 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// }

区块(块级效用域)
  • ES5:空头支票块级功用域
{
var a = 1;
}
console.log(a); // 1
  • ES6:使用let、const证明变量或常量(存在块级作用域)
{
let a = 1; const b =1;
}
console.log(a); // ReferenceError: a is not defined
console.log(b); // ReferenceError: a is not defined
{
let a = 1;
let a = 2;
console.log(a) //"SyntaxError: Identifier 'a' has already been declared(同一作用域重复声明一个变量报错)。
}
{
var a = 1;
var a = 2;
console.log(a);//2 var 重复声明同一变量取最后一次声明的赋值。
}

构造函数效果的优化达成

可是在那些写法中,我们一向将 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

本文由胜博发-前端发布,转载请注明来源:带你揭开call和apply改变this的真相sbf282.com,举个例