搞懂 JS this、call、apply、bind
创始人
2024-05-28 17:36:30
0

搞懂 JS this、call、apply、bind

javascript 的 this

ECMAScript 规范中这样写:
this 关键字执行为当前执行环境的 ThisBinding。
MDN 上这样写:
In most cases, the value of this is determined by how a function is called.
在绝大多数情况下,函数的调用方式决定了 this 的值。
可以这样理解,在 JavaScript 中,this 的指向是调用时决定的,而不是创建时决定的,这就会导致 this 的指向会让人迷惑,简单来说,this 具有运行期绑定的特性。

首先需要理解调用位置,调用位置就是函数在代码中被调用的位置,而不是声明的位置。

通过分析调用栈(到达当前执行位置所调用的所有函数)可以找到调用位置。

全局上下文
在全局执行上下文中 this 都指代全局对象。

this等价于window对象
var === this. === winodw.
console.log(window === this); // true
var a = 1;
this.b = 2;
window.c = 3;
console.log(a + b + c); // 6

在浏览器里面 this 等价于 window 对象,如果你声明一些全局变量,这些变量都会作为 this 的属性。

函数上下文
在函数内部,this 的值取决于函数被调用的方式。
直接调用
this 指向全局变量。

function foo(){return this;
}
console.log(foo() === window); // true

如何改变 this 指向

call()、apply()

this 指向绑定的对象上。

var person = {name: "test",age: 25
};
function say(job){console.log(this.name+":"+this.age+" "+job);
}
say.call(person,"FE"); // test:25
say.apply(person,["FE"]); // test:25

可以看到,定义了一个 say 函数是用来输出 name、age 和 job,其中本身没有 name 和 age 属性,我们将这个函数绑定到 person 这个对象上,输出了本属于 person 的属性,说明此时 this 是指向对象 person 的。

如果传入一个原始值(字符串、布尔或数字类型)来当做 this 的绑定对象, 这个原始值会被转换成它的对象形式(new String()),这通常被称为“装箱”。

call 和 apply 从 this 的绑定角度上来说是一样的,唯一不同的是它们的第二个参数。

bind()

this 将永久地被绑定到了 bind 的第一个参数。

bind 和 call、apply 有些相似。

var person = {name: "test",age: 25
};
function say(){console.log(this.name+":"+this.age);
}
var f = say.bind(person);
console.log(f());

call 和 apply 有什么区别

call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。

当调用一个函数时,可以赋值一个不同的 this 对象。this 引用当前对象,即 call 方法的第一个参数。

通过 call 方法,你可以在一个对象上借用另一个对象上的方法,比如 Object.prototype.toString.call([]),就是一个 Array 对象借用了 Object 对象上的方法。

语法 fun.call(thisArg[, arg1[, arg2[, …]]])

thisArg

在 fun 函数运行时指定的 this 值。需要注意的是下面几种情况

(1)不传,或者传 null,undefined, 函数中的 this 指向 window 对象
(2)传递另一个函数的函数名,函数中的 this 指向这个函数的引用,并不一定是该函数执行时真正的 this 值 (3)值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象,如 String、Number、Boolean
(4)传递一个对象,函数中的 this 指向这个对象

arg1, arg2, …

指定的参数列表。

语法与 call() 方法的语法几乎完全相同,唯一的区别在于,apply 的第二个参数必须是一个包含多个参数的数组(或类数组对象)。apply 的这个特性很重要,

在调用一个存在的函数时,你可以为其指定一个 this 对象。 this 指当前对象,也就是正在调用这个函数的对象。 使用 apply, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。

语法:fun.apply(thisArg[, argsArray])

bind() 函数会创建一个新函数(称为绑定函数)

bind 是 ES5 新增的一个方法
传参和 call 或 apply 类似
不会执行对应的函数,call 或 apply 会自动执行对应的函数
返回对函数的引用
语法 fun.bind(thisArg[, arg1[, arg2[, …]]])

下面例子:当点击网页时,EventClick 被触发执行,输出 JSLite.io p1 p2, 说明 EventClick 中的 this 被 bind 改变成了 obj 对象。如果你将 EventClick.bind(obj,‘p1’,‘p2’) 变成 EventClick.call(obj,‘p1’,‘p2’) 的话,页面会直接输出 JSLite.io p1 p2

var obj = {name:'JSLite.io'};
/*** 给document添加click事件监听,并绑定EventClick函数* 通过bind方法设置EventClick的this为obj,并传递参数p1,p2*/
document.addEventListener('click',EventClick.bind(obj,'p1','p2'),false);
//当点击网页时触发并执行
function EventClick(a,b){console.log(this.name, //JSLite.ioa, //p1b  //p2)
}

模拟实现 call

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

模拟实现 apply

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.fnreturn result;
}

相关内容

热门资讯

忙碌的暑假作文 忙碌的暑假作文(精选3篇)  无论在学习、工作或是生活中,大家总免不了要接触或使用作文吧,作文要求篇...
我的暑假生活作文450字 我的暑假生活作文450字(精选34篇)  在日常学习、工作抑或是生活中,大家都跟作文打过交道吧,作文...
中国传统节日作文700字 中国传统节日作文700字(精选51篇)  作文是经过人的思想考虑和语言组织,通过文字来表达一个主题意...
未来的海洋作文 有关未来的海洋作文合集六篇  在学习、工作或生活中,大家总少不了接触作文吧,借助作文可以宣泄心中的情...
林志炫《你永远不知道》歌词 林志炫《你永远不知道》歌词  久违的声线、从容的台风,以一首《你永远不知道》回归的林志炫在亮相瞬间就...
春节大扫除的作文 春节大扫除的作文(集合15篇)  在学习、工作乃至生活中,大家都跟作文打过交道吧,作文是经过人的思想...
孔明灯 孔明灯孔明灯1  今天,是一年一度的中秋佳节。盼到傍晚,我们一家来爷爷奶奶家吃了顿晚饭,舅妈提议一起...
感恩父亲节作文 感恩父亲节作文13篇  在日常生活或是工作学习中,大家对作文都再熟悉不过了吧,作文是从内部言语向外部...
寒假中的一件事作文 寒假中的一件事作文(通用31篇)  在生活、工作和学习中,大家都有写作文的经历,对作文很是熟悉吧,借...
清联家杜文秀题戏台对联 清联家杜文秀题戏台对联  演戏看戏心中有戏;  修枝打枝节外生枝。  ——题戏台(1)  杜文秀还喜...
国庆见闻作文600字 国庆见闻作文600字6篇国庆见闻作文600字1  今天是“十·一”国庆节,天气非常晴朗,我与爸爸妈妈...
七夕情人节的名言警句 关于七夕情人节的名言警句  天阶夜色凉如水,坐看牵牛织女星。小编收集了关于七夕情人节的`名言警句,欢...
我的周末作文 我的周末作文(通用5篇)  在日复一日的学习、工作或生活中,大家都经常接触到作文吧,借助作文可以宣泄...
国庆节趣事作文500字 国庆节趣事作文500字三篇  国庆节趣事作文500字一:  今天,是一个特别的日子。大家一定知道吧!...
节约型社会 Saving s... 节约型社会 Saving society  Recently,there has been an a...
国庆节优秀作文 国庆节优秀作文(精选34篇)  在平凡的学习、工作、生活中,许多人都写过作文吧,作文根据写作时限的不...
假如作文300字 假如作文300字五篇  在平平淡淡的日常中,大家都接触过作文吧,作文是从内部言语向外部言语的过渡,即...
买年货的作文 关于买年货的作文八篇  每一年的春节到来之前,家家户户都会准备好新年必备的年货,在这个特别的日子里,...
生活给我的启示作文 生活给我的启示作文  生活中,启示无处不在,也许是满树的春红,也许是寂寞的梧桐。生活总是在完美中留下...