this
是javascript中的一个关键字,并非是一个变量。
this
关键字指向的是一个对象,而指向哪个对象,或者是这个对象的值是什么取决于使用(调用)的方式和环境。
this
指向的值是可以通过手动方式去改变的,比如call
、 bind
、 apply
方法。
this
在严格模式和非严格模式下也会有差别。
注意:谈this
的指向是指在一个函数里面的this
的指向,如果不在函数里面或在全局函数中,那就要看具体环境:
- 浏览器:
this
指向window
(严格模式下为undefined
)
- node环境中:
this
指向 {}
函数中的this
指向谁完全取决于是如何 调用 这个函数的(只有在调用时才能确定this
的指向)
绑定规则优先级: new
绑定 > 显式绑定 > 隐式绑定 > 默认绑定
全局调用(默认绑定)
- 浏览器:
this
指向window
(严格模式下为undefined
)
- node环境中:
this
指向 {}
1 2 3 4 5 6 7 8
| let a = 0; function testWindow() { this.a = 1; console.log(this.a); console.log(window.a); console.log(this); } testWindow();
|
1 2 3 4 5 6 7
| let a = 1; function testStrict() { "use strict"; console.log(this); console.log(this.a); } testStrict();
|
隐式绑定
谁调用就指向谁。
当函数作为对象的方法调用时,this
通常指向该对象。
1 2 3 4 5 6 7 8 9
| const person = { name: 'Alice', greet() { console.log('Hello, ' + this.name); } };
person.greet();
|
修改一下:
1 2 3 4 5 6 7 8 9 10 11
| let obj = { name: 'obj', foo: function () { console.log(this); function test() { console.log(this); } test() } } obj.foo()
|
1 2 3 4 5 6 7 8 9
| let obj = { name: 'obj', foo: function () { console.log(this); } } let bar = obj.foo bar()
|
1 2 3 4 5 6 7 8 9 10 11
| function foo() { console.log(this); } function bar(fn) { fn() } let obj = { name: 'obj', foo: foo } bar(obj.foo)
|
函数作为参数时,参数函数叫做子函数,外面的函数叫父函数,子函数也叫回调函数,像这样的函数有很多,比如forEach
、setimeout
,这些函数里的参数函数也叫内置参数
记住:父函数有能力决定子函数this的指向,例如forEach
里第一个参数是一个函数,第二个参数就是this
绑定的对象,不写默认绑定window
new
绑定
不管是严格模式还是非严格模式,通过new 构造函数
, this
都是指向构造函数创建的对象实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function Test(a) { this.a = a; console.log(this.a); }
Test.prototype.say = function () { console.log(this); console.log(this.a); };
const t = new test(1); console.log(t);
t.say();
|
显式绑定
在 JavaScript 中,显式绑定是通过 call()
、 apply()
或者 bind()
方法来手动指定函数执行时的 this
上下文。这种绑定方式允许我们明确地指定函数执行时想要使用的对象,而不依赖于函数的调用方式。
call
call()
方法允许我们调用一个函数并指定函数执行时的 this
上下文,传入函数的参数为零散接收即传入的参数用” ,
“ 隔开。
1 2 3 4 5 6 7 8
| function greet() { console.log('Hello, ' + this.name); }
const person = { name: 'John' };
greet.call(person);
|
apply
apply()
方法与 call()
类似,但是传入的参数为数组而不是一系列的零散参数。
1 2 3 4 5 6 7 8 9
| function greet(greeting) { console.log(greeting + ', ' + this.name); }
const person = { name: 'John' }; const args = ['Hello'];
greet.apply(person, args);
|
bind
bind()
方法创建并返回一个新函数,将原始函数绑定到指定的对象,并可选地预先设定部分参数。(参数匹配遵从就近原则)
bind
的伪代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function greet() { console.log('Hello, ' + this.name); }
const person = { name: 'John' };
const greetPerson = greet.bind(person);
greetPerson();
|
注意与new
的优先级问题: new
优先级更高:
1 2 3 4 5 6 7 8
| function func() { console.log(this, this.__proto__ === func.prototype) }
boundFunc = func.bind(1) boundFunc()
|
1 2 3 4 5 6 7 8 9
| function func() { console.log(this, this.__proto__ === func.prototype) }
boundFunc = func.bind(1)
new boundFunc()
|
多次bind
只认第一次的bind
:
1 2 3 4 5
| function func() { console.log(this) }
func.bind(1).bind(2)()
|
箭头函数
箭头函数没有 this
箭头函数的this
指向谁取决于该箭头函数定义的位置,而不是运行的位置 。因为它是基于闭包的,而闭包是基于词法作用域的。
技巧: 箭头函数的this
看外层是否有函数
- 如果有,外层函数的
this
就是内部箭头函数的this
- 如果没有,
this
就是window
箭头函数的 this
是在创建它时外层 this
的指向。这里的重点有两个:
- 创建箭头函数时,就已经确定了它的
this
指向。
- 箭头函数内的
this
指向外层的 this
。
1 2 3 4 5 6
| func = () => { console.log(this) }
func.bind(1)()
|
1 2 3 4 5 6
| func = () => { console.log(this) }
func.apply(1)
|
独立调用对箭头函数无效
1 2 3 4 5 6 7 8 9 10
| let a = 0 function foo() { let test = () => { console.log(this) } return test } let obj = { a: 1, foo: foo } obj.foo()()
|
隐式绑定对箭头函数无效
1 2 3 4 5 6 7 8
| let a = 0 let obj1 = { a: 1, foo: () => { console.log(this); } } obj1.foo()
|
显式绑定对箭头函数无效
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| let a = 0 function foo() { let test = () => { console.log(this) } return test } let obj1 = { a: 1, foo: foo } let obj2 = { a: 2, foo: foo } obj1.foo().call(obj2)
|
事件处理函数
在事件处理函数中,this
指向被绑定的目标对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <body> <button id="btn">click</button> <button id="btn1">click1</button> <script>
const btn = document.getElementById("btn"); btn.onclick = function () { console.log(this); this.innerHTML = "loading.."; this.disabled = true; };
const btn1 = document.getElementById("btn1"); btn1.onclick = () => { console.log(this); }; </script> </body>
|
内联函数
以下代码包含了严格模式和非严格模式不同的情况:
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
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body>
<button onclick=" alert(this);">内联事件处理0</button> //元素本身即button
<button onclick="alert((function(){'use strict'; return this})());">内联事件处理1</button>
//undefined
<button onclick="alert((function(){ return this})());">内联事件处理2</button>
//window
<button onclick="'use strict'; alert(this.tagName.toLowerCase());">内联事件处理3</button>
//button
</body> </html>
|