一、认识函数的上下文
- 什么是上下文text
垃圾分类,`这`是非常好的习惯,值得表扬 随手关灯,`这`是非常好的习惯,值得表扬 遛狗栓绳,`这`是非常好的习惯,值得表扬 课后复习,`这`是非常好的习惯,值得表扬 早睡早起,`这`是非常好的习惯,值得表扬
- 函数的上下文
- 函数中可以使用
this
关键字,它表示函数的上下文
。 - 与中文中"这"类似,函数中的this具体指代什么
必须通过调用函数时的"前言后语"来判断
- 函数中可以使用
- 函数中的thisjs
var xiaoming = { nickname: '小明', age: 12, sayHello: function () { console.log('我是' + this.nickname + ',我' + this.age + '岁了'); } }; xiaoming.sayHello(); // 我是小明,我12岁了
jsvar xiaoming = { nickname: '小明', age: 12, sayHello: function () { console.log('我是' + this.nickname + ',我' + this.age + '岁了'); } }; var sayHello = xiaoming.sayHello; // 将函数"提"出来,单独存为变量 // 直接圆括号调用这个函数,而不是对象打点调用了 sayHello(); // 我是undefined,我undefined岁了
- 函数的上下文由调用方式决定
- 同一个函数,用不同的形式调用它,则函数的上下文不同
- 情形1:对象打点调用函数,函数中的
this
指代这个打点的对象
。jsxiaoming.sayHello();
- 情形2:圆括号直接调用函数,函数中的
this
指代window对象
。jsvar sayHello = xiaoming.sayHello; sayHello();
jsvar obj = { a: 1, b: 2, fn: function () { console.log(this.a + this.b); } }; var fn = obj.fn; fn();
- 情形1:对象打点调用函数,函数中的
- 同一个函数,用不同的形式调用它,则函数的上下文不同
1. 上下文规则1
函数的上下文由调用函数的方式决定
- 函数的上下文(this关键字)由
调用函数
的方式决定, function是"运行时上下文"
策略。 - 函数如果不调用,则不能确定函数的上下文。
- 函数的上下文(this关键字)由
规则1:
对象打点调用它的方法函数,则函数的上下文是这个打点的对象
。 对象.方法()jsfunction fn() { console.log(this.a + this.b); } var obj = { a: 66, b: 33, fn: fn }; obj.fn(); // 99
- 构成对象.方法()的 形式,适用规则1
jsvar obj1 = { a: 1, b: 2, fn: function () { console.log(this.a + this.b); } }; var obj2 = { a: 3, b: 4, fn: obj1.fn }; obj2.fn(); // 7
- 构成对象.方法()的形式,适用规则1
jsfunction outer() { var a = 11; var b = 22; return { a: 33, b: 44, fn: function () { console.log(this.a + this.b); } }; } outer().fn(); // 77
- 构成对象.方法()的 形式,适用规则1
jsfunction fun() { console.log(this.a + this.b); } var obj = { a: 1, b: 2, c: [{ a: 3, b: 4, c: fun }] }; var a = 5; obj.c[0].c(); // 7
- 构成对象.方法()的形式,适用规则1
2. 上下文规则2
规则2:圆括号直接调用函数,则函数的上下文是window对象
js函数()
jsvar obj1 = { a: 1, b: 2, fn: function () { console.log(this.a + this.b); } }; var a = 3; var b = 4; var fn = obj1.fn; fn(); // 7
- 构成函数()的形式,适用规则2
jsfunction fun() { return this.a + this.b; } var a = 1; var b = 2; var obj = { a: 3, b: fun(), // 适用规则2 fun: fun }; var result = obj.fun(); // 适用规则1 console.log(result); // 6
3. 上下文规则3
规则3:数组(类数组对象)枚举出函数进行调用,上下文 是这个数组(类数组对象)
js数组[下标]()
jsvar arr = ['A', 'B', 'C', function () { console.log(this[0]); }]; arr[3](); // "A"
- 适用规则3
什么是类数组对象:所有键名为自然数序列(从0开始),且有
length
属性的对象。arguments对象是最常见的类数组对象,它是函数的实参列表。
jsfunction fun() { arguments[3](); } fun('A', 'B', 'C', function () { console.log(this[1]); // 'B' });
- 适用规则3
4. 上下文规则4
- 规则4:
IIFE中的函数,上下文是window对象
。js(function() {})();
jsvar a = 1; var obj = { a: 2, fun: (function () { var a = this.a; return function () { console.log(a + this.a); // 3 } })() // 适用规则4 }; obj.fun(); // 适用规则1
5. 上下文规则5
- 规则5:定时器、延时器调用函数,上下文是window对象js
setInterval(函数, 时间); setTimeout(函数, 时间);
jsvar obj = { a: 1, b: 2, fun: function () { console.log(this.a + this.b); // 7 } } var a = 3; var b = 4; setTimeout(obj.fun, 2000); // 适用规则5
jsvar obj = { a: 1, b: 2, fun: function () { console.log(this.a + this.b); // 3 } } var a = 3; var b = 4; setTimeout(function() { obj.fun(); // 适用规则1 }, 2000);
6. 上下文规则6
- 规则6:事件处理函数的上下文是绑定事件的DOM元素。js
DOM元素.onclick = function () {};
- 请实现效果:点击哪个盒子,哪个盒子就变红,要求使用同一个事件处理函数实现。html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ width: 200px; height: 200px; float: left; border: 1px solid #000; margin-right: 10px; } </style> </head> <body> <div id="box1"></div> <div id="box2"></div> <div id="box3"></div> <script> function setColorToRed() { this.style.backgroundColor = 'red'; } var box1 = document.getElementById('box1'); var box2 = document.getElementById('box2'); var box3 = document.getElementById('box3'); box1.onclick = setColorToRed; box2.onclick = setColorToRed; box3.onclick = setColorToRed; </script> </body> </html>
- 请实现效果:点击哪个盒子,哪个盒子在2000毫秒后就变红,要求使用同一个事件处理函数实现。html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div{ width: 200px; height: 200px; float: left; border: 1px solid #000; margin-right: 10px; } </style> </head> <body> <div id="box1"></div> <div id="box2"></div> <div id="box3"></div> <script> function setColorToRed() { // 备份上下文 var self = this; setTimeout(function() { self.style.backgroundColor = 'red'; }, 2000); } var box1 = document.getElementById('box1'); var box2 = document.getElementById('box2'); var box3 = document.getElementById('box3'); box1.onclick = setColorToRed; box2.onclick = setColorToRed; box3.onclick = setColorToRed; </script> </body> </html>
7. call 和 apply
call
和apply
能指定函数的上下文。jsfunction sum() { alert(this.chinese + this.math + this.english); } var xiaoming = { chinese: 80, math: 95, english: 93 }; sum.call(xiaoming); sum.apply(xiaoming);
- 函数.call(上下文);
- 函数.apply(上下文);
call
和apply
的区别jsfunction sum(b1, b2) { alert(this.c + this.m + this.e + b1 + b2); } sum.call(xiaoming, 5, 3); // call要用逗号罗列参数x sum.apply(xiaoming, [5, 3]); // apply要把参数写到数组中
到底使用call还是apply?
jsfunction fun1() { fun2.apply(this, arguments); } function fun2(a, b) { alert(a + b); } fun1(33, 44);
8. 总结
规则 | 上下文 |
---|---|
对象.函数() | 对象 |
函数() | window |
数组[下标]() | 数组 |
IIFE | window |
定时器 | window |
DOM事件处理函数 | 绑定DOM的元素 |
call和apply | 任意指定 |