为什么要有this
1.为了让对象中的函数有能力访问对象自己的属性。
例子
如果我们想要在对象内部方法中使用对象内部的属性,就像图中的代码,它是可以在C语言里运行的,但是在JS中不可行,JS它需要使用this机制来访问(图中的myName)
1let obj = {
2 myName: '喜羊羊',
3 age: 12,
4 bar: function () {
5 console.log(this.myName);
6 }
7}
8obj.bar();
2.this可以显著的提升代码质量,减少上下文参数的传递。
这种显示传参的方法有点啰嗦,如果我们采用this的话,那么就会优雅,方便很多。
1function identify() {
2 return this.name.toUpperCase();
3}
4
5function speak() {
6 var greeting = 'Hello, I am ' + identify.call(this);
7 console.log(greeting);
8}
9
10var me = {
11 name: 'gg bond'
12}
13
14speak.call(me);
运行结果是一样的
this的使用场景
可以产生作用域的地方就可以用this(除了块级作用域)
也就是:
- 全局
- 函数体内
1console.log(this);
在node里打印出来是:
因为node的全局是global空对象,跟浏览器的引擎有些不一样,我们看在浏览器上的运行:
全局代指的是Window
this 代指某一块作用域
写在全局下面就代指全局的作用域
this的绑定规则
1. 默认绑定
当一个函数直接独立调用,不带任何修饰符时,使用默认绑定。 - 函数在哪个词法作用域中生效,函数中的this就指向哪里。(只要是默认绑定this一定指向全局对象window。 )
1function foo() {
2 console.log(this);
3}
4foo();
1function foo() {
2 console.log(this);
3}
4function bar() {
5 foo();
6}
7bar()
var
在全局,通过var
声明的变量相当于window.xxx
,在window
对象上添加了一个属性在函数中,通过var声明的变量相当于函数的词法作用域。
let
就不会
2. 隐式绑定
当函数的引用有上下文对象时(当函数被某个对象所拥有时),隐式绑定。 - 函数中的this指向的是引用它的对象。
1var obj = {
2 a: 1,
3 foo: foo
4}
5
6function foo() {
7 console.log(this.a);
8}
9
10obj.foo()
3. 隐式丢失
当一个函数被赋值被多个对象链式调用时,函数的this指向就近的那个对象
1我附庸的附庸不是我的附庸
1var obj = {
2 a: 1,
3 foo: foo
4}
5
6var obj2 = {
7 a: 2,
8 obj: obj
9}
10
11function foo() {
12 console.log(this.a);
13}
14
15obj2.obj.foo()
4. 显示绑定
通过bind、apply、call,将函数的this指向指定的对象。call直接接受参数,apply接受参数需要用数组装起来。
bind()
band()会默认返回一个函数体。
当这个新函数被调用时,它的 this
值会被设置为在 bind()
调用中传递的第一个参数。
1function greet(greeting) {
2 console.log(greeting + ', ' + this.name);
3}
4
5let person = { name: 'GG Bond' };
6
7let greetJohn = greet.bind(person, 'Hello');
8greetJohn();
call()
立即调用一个函数,并允许指定 this
值以及任何需要传递给函数的参数。参数直接列在 call()
后面,不需要用数组包装。
1function greet(greeting) {
2 console.log(greeting + ', ' + this.name);
3}
4
5let person = { name: 'call' };
6
7greet.call(person, 'Hi');
apply()
apply()
也立即调用一个函数,但与 call()
不同的是,它的参数需要以数组的形式给出。
1var obj = {
2 a: 1
3}
4
5function foo(x, y) {
6 console.log(this.a, x + y);
7}
8foo.apply(obj, [1, 2])
6. new绑定
通过new调用函数,将函数的this指向新创建的对象。
创建对象并绑定 this
的过程:
- 创建一个新对象:首先,JavaScript 引擎会创建一个全新的空对象。
- 设置原型链:新对象的原型(
__proto__
)会被设置为构造函数的prototype
属性所指向的对象。 - 绑定 this:函数内部的
this
被绑定到这个新创建的对象上。 - 执行构造函数:构造函数的代码被执行,
this
指向新创建的对象。 - 返回新对象:如果构造函数没有显式返回一个对象,则默认返回新创建的对象。如果构造函数返回了一个对象,那么这个返回的对象将覆盖新创建的对象。
1function Person(name) {
2 this.name = name;
3 return {};
4}
5let jane = new Person('Jane');
6console.log(jane instanceof Object);
7console.log(jane instanceof Person);
8
7. 箭头函数
箭头函数中没有this
这个机制,写在箭头函数中的this
也是它外层非箭头函数的。
1function regularFunction() {
2 console.log(this);
3}
4
5
6const arrowFunction = () => {
7 console.log(this);
8};
9
10
11const obj = {
12 name: 'Test',
13 regularMethod: function() {
14 console.log(this);
15 },
16 arrowMethod: () => {
17 console.log(this);
18 }
19};
20
21
22regularFunction();
23arrowFunction();
24
25
26obj.regularMethod();
27obj.arrowMethod();