apply,call,bind

Function.prototype.call(thisArg [, arg1, arg2, ...])

概述

call()方法调用一个函数,其具有一个指定的this值和分别提供的参数(参数的列表)。
当第一个参数为null、undefined时, 默认this上下文指向window

简单实例

const name = 'qianyin';
const product = {
  name: 'linheng',
};
function log(...args){
  console.log(this.name, ...args);
}

log(1, 2, 3);               // qianyin 1 2 3
log.call(null, 1, 2, 3);    // qianyin 1 2 3
log.call(product, 1, 2, 3); // linheng 1 2 3

对箭头函数无效

const name = 'qianyin';
const product = {
  name: 'linheng',
};

const log = (...args) => {
  console.log(this.name, ...args);
}

log(1, 2, 3);               // qianyin 1 2 3
log.call(null, 1, 2, 3);    // qianyin 1 2 3
log.call(product, 1, 2, 3); // qianyin 1 2 3

箭头函数作为函数的一种形式, 对于this的处理和普通函数有所区别, 其没有自己的this上下文,也就是说通过bind/call/apply函数方法设置this值时无效的,会被忽略。

因为箭头函数没有自己的this上下文, 所以箭头函数的this上下文等于定义函数处的this上下文,也就是最近的一个this上下文。

你可以认为箭头函数的this和调用者无关,只和其定义时所在的this上下文相关。

如下代码: 在对象obj中使用箭头函数定义log函数, 那么因为箭头函数没有自己的this上下文, 所以log函数的this上下文等于定义箭头函数处的this上下文, 等于对象obj所处的this上下文(window)。

const name = 'linheng';
const obj = {
  name: 'qianyin',
  log: () => {
    console.log(this.name);
  }
};
obj.log();  // linheng

obj中定义一个log函数并且使得this指向对象obj的方法:

const name = 'linheng';
const obj = {
  name: 'qianyin',
  log: function(){
    console.log(this.name);
  }
};
obj.log();  // qianyin

Function.prototype.apply(thisArg [, Array])

概述

apply()方法 调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数call()方法的作用和apply()方法类似,区别就是除了第一参数call()方法接受的是参数列表 ,而apply()方法接受的是一个参数数组(或类数组)。

简单实例

var name = 'qianyin';
var product = {
  name: 'linheng',
};

function log(...args){
  console.log(this.name, ...args);
}

log([1, 2, 3]);                 // qianyin [1 2 3]
log.apply(null, [1, 2, 3]);     // qianyin 1 2 3
log.apply(product, [1, 2, 3]);  // linheng 1 2 3

对箭头函数无效

const name = 'qianyin';
const product = {
  name: 'linheng',
};

const log = (...args) => {
  console.log(this.name, ...args);
}

log([1, 2, 3]);                 // qianyin [1 2 3]
log.apply(null, [1, 2, 3]);     // qianyin 1 2 3
log.apply(product, [1, 2, 3]);  // qianyin 1 2 3

Function.prototype.bind(thisArg [, arg1, arg2, ...])

概述

bind()方法创建(拷贝)一个新的函数 , 当这个新函数被调用时this指向thisArg,其参数列表前几项值为创建时指定的参数序列。
thisArg: 绑定函数被调用时,该参数会作为原函数运行时的this指向。当使用new操作符调用绑定函数时,该参数无效。

bind() 绑定this上下文

bind()最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的this上下文。
JavaScript新手经常犯的一个错误是将一个方法从对象中拿出来,然后再调用,却又希望方法中的this是原来的对象(比如在回调中传入这个方法)。
如果不做特殊处理的话,一般会丢失原来的对象。从原来的函数和原来的对象创建一个绑定函数,则能很漂亮地解决这个问题:
如果只是单纯绑定this上下文, 完全可以使用箭头函数进行替代。

// 例一
this.x = 9;

var module = {
  x: 81,
  getX: function() { return this.x; }
};
module.getX();  // 返回 81 (通过对象调用函数, 上下文为该对象)
var retrieveX = module.getX;  // 获取对象中函数的引用地址
retrieveX();    // 返回 9, 在这种情况下, "this" 指向全局作用域(在全局对象下调用函数)
// 永久为函数 boundGetX 绑定 this 上下文
var boundGetX = retrieveX.bind(module);
boundGetX();   // 返回 81 (函数 this 上下文永久绑定为 module)
// 例二为回调函数绑定 this 上下文
var x = 10;
var obj = {
  x: 20,
  get: ffunction(){
    console.log(this.x);
  }
};
// 将对象中方法取出(函数的引用地址),作为回调函数, 又因为 setTimeout 回调函数执行的上下文是 window
setTimeout(obj.get, 1000);            // 打印 10
// 将对象中方法取出(函数的引用地址),作为回调函数并绑定 this 上下文
setTimeout(obj.get.bind(obj), 1000);  // 打印 20

为函数永久绑定固定参数

bind()的另一个最简单的用法是使一个函数拥有预设的初始参数。
这些参数(如果有的话)作为bind()的第二个参数跟在this(或其他对象)后面。
之后它们会被插入到目标函数的参数列表的开始位置 ,传递给绑定函数的参数会跟在它们的后面。

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// 为拷贝 list 方法并绑定初始参数
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList();         // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

apply call bind 的一些运用

类数组转为数组

// 方法一:
const obj = {0: 'q', 1: 'i', 2: 'q', 3: 'a',  4:'n', 5: 'y', 6:'i', 7:'n', length: 8};
const arr = [];
Array.prototype.push.apply(arr, obj);
console.log(arr); // ["q", "i", "q", "a", "n", "y", "i", "n"]
// 方法二:
const obj = {0: 'q', 1: 'i', length: 2};
const arr = Array.prototype.slice.call(obj);  // [q, i]

为伪数组添加新的元素

// 方法一: 当然你也可以使用 apply
const obj = {0: 'q', length: 1};
Array.prototype.push.call(obj, 'i', 'a', 'n');
console.log(obj);   // {0: 'q', 1: 'i', 2: 'a', 3: 'n'}
// 方法二:
const obj = {0: 'q', length: 1};
const push = Array.prototype.push.bind(obj);
push('i', 'a', 'n');
console.log(obj);   // {0: 'q', 1: 'i', 2: 'a', 3: 'n'}

求数组中最大值(最小值一样做法)

const arr = [1,2,3,4,5,6];
const max = Math.max.apply(null, arr);
// 或 const max = Math.max.call(null, ...arr)
console.log(max);    // 6

数组合并追加

const arr = [1, 2];
const brr = [3, 4];
Array.prototype.push.apply(arr, brr);
// 或者 Array.prototype.push.call(arr, ...brr);
// 当然还可以这样 arr.push(...brr);
console.log(arr); // [1, 2, 3, 4]

总结

  • 当我们使用一个函数需要改变this指向的时候才会用到call()、apply()、bind()当然也别忘记了箭头函数
  • call()apply()是对函数的调用,在调用的同时绑定this上下文并传递参数列表
  • bind()是对函数的拷贝进一步的封装,为函数永久绑定this上下文并赋予固定参数
  • call()bind()以参数列表形式给函数指定参数,apply()则以数组的形式给函数指定参数
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容