首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

  • 24-12-05 23:15
  • 3390
  • 6571
juejin.cn

为什么要有this

我们看下面的代码例子

js
代码解读
复制代码
function identify(context) { return context.name.toUpperCase() } function speak(context) { var gretting = 'Hello,I am' + identify(context) console.log(gretting); } var me = { name: 'Tom' } speak(me)

在这段代码中,我们是想实现传参并将传入参数的字符全部变为大写,最后输出(Hello,I am(我们传入参数的大写))然后我们写了两个函数 speak,identify,在这里我们并没有调用this关键字,执行speak,将me对象传入speak对象中,然后调用对象的name属性,但是为了实现将属性的内容大写,我们又要使用到identify的函数,并要将对象me传入identify中,实现这个功能并返回,最后进行输出,下面是执行结果

34.png

但这样子的话,但凡我们需要添加一个新功能,就必须在所写的函数中进行传参,这样的话一个参数被传到几十个函数里,会导致十分混乱

让我们来使用this关键字优化一下

js
代码解读
复制代码
function identify() { return this.name.toUpperCase() } function speak() { var gretting = 'Hello,I am' + identify.call(this) console.log(gretting); } var me = { name: 'Tom' } speak.call(me)

可以看到,在两个函数中,我们并没有进行传参,而是用this代表了我们想传入的对象,看看执行结果是否和上面一样

35.png

可以看到运行结果是一样的,所以我们得出一个结论;this 让函数可以自动引用合适的上下文对象

this的概念

我们要先明白一些this的概念;this 是一个非常重要的关键字,它永远是一个代词,在js中永远代指某一个域,且this只在域中存在才有意义。 在全局作用域下它代指(在浏览器中是window,在Node.js中是global),下面是代码验证

36.png 可以看到this在全局下指向的是(在浏览器中是window,在Node.js中是global)

this的绑定规则

默认绑定

函数独立调用,this指向window

js
代码解读
复制代码
function foo(){ let person = { name: '彭于晏', age: 42 } console.log(this); } foo()

让我们来分析一下这段代码,在这段代码中,我们写了一个foo函数并执行,可以看到this关键字写在foo里面,属于foo函数,那这个this代指谁呢,我们来看看输出结果

37.png 可以看到这个this还是代指的(在浏览器中是window,在Node.js中是global),我们再看看下面的代码

js
代码解读
复制代码
function foo(){ let person = { name: '彭于晏', age: 42 } console.log(this); } function bar() { let person ={ name: '金城武', age:51 } foo() } bar()

这段代码中,我们又创建了一个bar函数并将foo函数放入bar函数中执行,将bar函数放入全局中执行,此时this关键字还是属于foo函数,但foo函数从在全局执行变成了在bar函数中执行,那此时this代指谁呢?我们来看看结果

38.png

可以看到,此时this代指的还是(在浏览器中是window,在Node.js中是global)

可以得出this的绑定和和所在函数的位置没有关系,当this所在函数独立调用的时候,它绑定的就是(在浏览器中是window,在Node.js中是global)。

隐式绑定

当函数的引用有上下文对象(当函数被某一个对象所拥有且调用)this指向该上下文对象

js
代码解读
复制代码
function foo(){ console.log(this); } const obj ={ a: 1, foo: foo } obj.foo()

在这段代码中我们创建了foo函数和obj对象,并在obj对象当中将foo函数添加进去了,最后在全局下调用obj对象并执行,那此时foo中的this绑定了谁呢

下面是代码的执行结果

39.png

可以看到此时this代表的就是调用函数foo的对象obj了

那当函数的引用有一连串上下文对象,this指向谁呢

js
代码解读
复制代码
function foo(){ console.log(this.a); } const obj ={ a: 1, foo: foo } const obj2 = { a: 2, obj: obj } obj2.obj.foo()

在这段代码中foo()属于obj,obj属于obj2,所以foo也属于obj,那此时foo函数中的this代指谁呢,这里只需遵守一个就近原则,那就是离函数近的那一个,下面是代码执行结果

40.png 我们可以得出结论;当函数的引用有一连串上下文对象,this指向最近的那个对象

显示绑定

调用call apply bind方法显示的将函数的this绑定到一个对象上 我们来看看实例

js
代码解读
复制代码
function foo() { console.log(this.a); } var obj = { a: 1 } foo()

在这段代码中,我们独立调用foo函数,因此foo中的this应该是指向全局,但是全局中没有a,因此打印出来的就是undefined,那我们想让this不用隐式绑定去绑定在obj对象上,可以怎么样呢

js
代码解读
复制代码
function foo() { console.log(this.a); } var obj = { a: 1 } foo.call(obj)

我们可以使用call方法强行将foo中的this指向obj,下面是运行结果

41.png

可以看到我们实现想要的效果了,this的指向被强行指向了obj

那如果函数foo需要接收参数呢

js
代码解读
复制代码
function foo(x,y) { console.log(this.a,x+y); } var obj = { a: 1 } foo.call(obj)

此时怎么给foo函数进行传参呢,要弄懂这个问题,我们要先知道foo是怎么被执行的,在这段代码中我们只是使用了call方法,并没有去人为触发foo函数,其实就是在call方法中帮我们触发了foo函数,所以本来是foo接受的参数call也会帮我们接收

js
代码解读
复制代码
function foo(x,y) { console.log(this.a,x+y); } var obj = { a: 1 } foo.call(obj,2,3)

看看结果是否正确

42.png

没有问题,结果正常输出了

除了call方法还有apply方法,它们俩的区别就是接收参数时call是零散的接收,而apply是通过数组去接收 foo.call(obj,2,3),foo.apply(obj,[2,3]),还有一个和call方法一样,只是需要函数体去接收 let bar=foo. bind(obj,2,3),然后再执行bar,我们也可以将参数传入接收的函数体中let bar=foo. bind(obj),bar(2,3)

new绑定

提到new,我们可以先了解一下new的原理下面的文章有进行讲解 juejin.cn/post/743932…

js
代码解读
复制代码
function Person() { this.name = '彭于晏', this.age = 42 } let p = new Person() console.log(p);

在这段代码中this的指向是谁呢,在new的原理中,我们知道我们创建了一个对象,且当函数内部存在return且返回的是一个引用数据类型的时候,new的执行结果就是这个引用类型的数据,而this的绑定就是new创建出来的这个对象,所以我们打印出来new中创建对象的数据,下面是代码执行结果

43.png

箭头函数

1,箭头函数没有this,写在箭头函数中的this那也是它外层的非箭头函数的

js
代码解读
复制代码
function foo() { let bar = function () { let baz = () => { let fn = () => { console.log(this); } fn() } baz() } bar() } foo()

看这段代码,this写在fn箭头函数里面,那这个this属于谁呢,我们要知道箭头函数里面没有this,所以我们要一层一层往外判断首先fn是箭头函数,所以不是它的,然后是baz,baz也是箭头函数所以也不是baz的,然后是bar,bar不是箭头函数,所以this是属于bar函数的

2,箭头函数不能作为构造函数使用

js
代码解读
复制代码
let Foo = () => { this.name = '廖总' } let foo = new Foo()

在这段代码中,我们想得到一个对象foo,那我们能通过new关键字从箭头函数中来获得foo对象吗?看看代码运行结果

44.png 这里报错了,所以箭头函数是不能作为构造函数使用的。

call方法的实现原理

call方法可以直接将函数的this绑定在对象上,其实也是用了隐式绑定规则进行了非独立调用,将函数将 foo 引用到 obj 上,让 obj 调用foo,移除obj上的 foo,让我们来手搓一个效果一样的方法

js
代码解读
复制代码
function foo(x, y) { console.log(this.a); return x + y; } const obj = { a: 1 } Function.prototype.myCall = function (...args) { const context = args[0] const arg = args.slice(1) // [2, 3, 4] context.fn = this const res = context.fn(...arg) delete context.fn return res } let res = foo.myCall(obj, 2, 3, 4) console.log(res);

这段代码上我们在Function函数的原型上创建了一个myCall的方法形参...args表示将传入的实参以数组的方式使用,然后我们线拿到数组下标为0的对象,然后将剩下的内容分割出来然后我们用给传入对象也就是context添加一个fn属性,这个fn属性我们需要变为foo函数使对象能够调用这个函数,而在全局中myCall是由foo进行的隐式调用所以在myCall方法中,this表示的就是foo,我们将它添加到对象当中,然后让context 调用foo,我们知道在这里arg是分割后的数组,我们再用一下...arg可以将数组里的元素拆解出来,然后交给foo进行调用并将调用结果给res然后我们不能真的给obj对象中添加foo函数,所以要将其删除,最后将obj 调用foo的结果进行返回,所以最后foo.myCall(obj, 2, 3, 4)的效果与obj.foo(2, 3, 4)是一样的,我们来看看输出结果

45.png

输出结果我们们分析的预期是一样的

总结

this关键字在JavaScript中用于指代当前执行上下文的对象。通过使用this,可以简化对象内部方法的参数传递,使代码更加简洁和易于维护。this的绑定规则包括默认绑定、隐式绑定、显示绑定(call、apply、bind)和new绑定。箭头函数没有自己的this,而是继承外层函数的this。理解this的概念和绑定规则对于编写高效的JavaScript代码至关重要。

为什么要有this

我们看下面的代码例子

js
代码解读
复制代码
function identify(context) { return context.name.toUpperCase() } function speak(context) { var gretting = 'Hello,I am' + identify(context) console.log(gretting); } var me = { name: 'Tom' } speak(me)

在这段代码中,我们是想实现传参并将传入参数的字符全部变为大写,最后输出(Hello,I am(我们传入参数的大写))然后我们写了两个函数 speak,identify,在这里我们并没有调用this关键字,执行speak,将me对象传入speak对象中,然后调用对象的name属性,但是为了实现将属性的内容大写,我们又要使用到identify的函数,并要将对象me传入identify中,实现这个功能并返回,最后进行输出,下面是执行结果

34.png

但这样子的话,但凡我们需要添加一个新功能,就必须在所写的函数中进行传参,这样的话一个参数被传到几十个函数里,会导致十分混乱

让我们来使用this关键字优化一下

js
代码解读
复制代码
function identify() { return this.name.toUpperCase() } function speak() { var gretting = 'Hello,I am' + identify.call(this) console.log(gretting); } var me = { name: 'Tom' } speak.call(me)

可以看到,在两个函数中,我们并没有进行传参,而是用this代表了我们想传入的对象,看看执行结果是否和上面一样

35.png

可以看到运行结果是一样的,所以我们得出一个结论;this 让函数可以自动引用合适的上下文对象

this的概念

我们要先明白一些this的概念;this 是一个非常重要的关键字,它永远是一个代词,在js中永远代指某一个域,且this只在域中存在才有意义。 在全局作用域下它代指(在浏览器中是window,在Node.js中是global),下面是代码验证

36.png 可以看到this在全局下指向的是(在浏览器中是window,在Node.js中是global)

this的绑定规则

默认绑定

函数独立调用,this指向window

js
代码解读
复制代码
function foo(){ let person = { name: '彭于晏', age: 42 } console.log(this); } foo()

让我们来分析一下这段代码,在这段代码中,我们写了一个foo函数并执行,可以看到this关键字写在foo里面,属于foo函数,那这个this代指谁呢,我们来看看输出结果

37.png 可以看到这个this还是代指的(在浏览器中是window,在Node.js中是global),我们再看看下面的代码

js
代码解读
复制代码
function foo(){ let person = { name: '彭于晏', age: 42 } console.log(this); } function bar() { let person ={ name: '金城武', age:51 } foo() } bar()

这段代码中,我们又创建了一个bar函数并将foo函数放入bar函数中执行,将bar函数放入全局中执行,此时this关键字还是属于foo函数,但foo函数从在全局执行变成了在bar函数中执行,那此时this代指谁呢?我们来看看结果

38.png

可以看到,此时this代指的还是(在浏览器中是window,在Node.js中是global)

可以得出this的绑定和和所在函数的位置没有关系,当this所在函数独立调用的时候,它绑定的就是(在浏览器中是window,在Node.js中是global)。

隐式绑定

当函数的引用有上下文对象(当函数被某一个对象所拥有且调用)this指向该上下文对象

js
代码解读
复制代码
function foo(){ console.log(this); } const obj ={ a: 1, foo: foo } obj.foo()

在这段代码中我们创建了foo函数和obj对象,并在obj对象当中将foo函数添加进去了,最后在全局下调用obj对象并执行,那此时foo中的this绑定了谁呢

下面是代码的执行结果

39.png

可以看到此时this代表的就是调用函数foo的对象obj了

那当函数的引用有一连串上下文对象,this指向谁呢

js
代码解读
复制代码
function foo(){ console.log(this.a); } const obj ={ a: 1, foo: foo } const obj2 = { a: 2, obj: obj } obj2.obj.foo()

在这段代码中foo()属于obj,obj属于obj2,所以foo也属于obj,那此时foo函数中的this代指谁呢,这里只需遵守一个就近原则,那就是离函数近的那一个,下面是代码执行结果

40.png 我们可以得出结论;当函数的引用有一连串上下文对象,this指向最近的那个对象

显示绑定

调用call apply bind方法显示的将函数的this绑定到一个对象上 我们来看看实例

js
代码解读
复制代码
function foo() { console.log(this.a); } var obj = { a: 1 } foo()

在这段代码中,我们独立调用foo函数,因此foo中的this应该是指向全局,但是全局中没有a,因此打印出来的就是undefined,那我们想让this不用隐式绑定去绑定在obj对象上,可以怎么样呢

js
代码解读
复制代码
function foo() { console.log(this.a); } var obj = { a: 1 } foo.call(obj)

我们可以使用call方法强行将foo中的this指向obj,下面是运行结果

41.png

可以看到我们实现想要的效果了,this的指向被强行指向了obj

那如果函数foo需要接收参数呢

js
代码解读
复制代码
function foo(x,y) { console.log(this.a,x+y); } var obj = { a: 1 } foo.call(obj)

此时怎么给foo函数进行传参呢,要弄懂这个问题,我们要先知道foo是怎么被执行的,在这段代码中我们只是使用了call方法,并没有去人为触发foo函数,其实就是在call方法中帮我们触发了foo函数,所以本来是foo接受的参数call也会帮我们接收

js
代码解读
复制代码
function foo(x,y) { console.log(this.a,x+y); } var obj = { a: 1 } foo.call(obj,2,3)

看看结果是否正确

42.png

没有问题,结果正常输出了

除了call方法还有apply方法,它们俩的区别就是接收参数时call是零散的接收,而apply是通过数组去接收 foo.call(obj,2,3),foo.apply(obj,[2,3]),还有一个和call方法一样,只是需要函数体去接收 let bar=foo. bind(obj,2,3),然后再执行bar,我们也可以将参数传入接收的函数体中let bar=foo. bind(obj),bar(2,3)

new绑定

提到new,我们可以先了解一下new的原理下面的文章有进行讲解 juejin.cn/post/743932…

js
代码解读
复制代码
function Person() { this.name = '彭于晏', this.age = 42 } let p = new Person() console.log(p);

在这段代码中this的指向是谁呢,在new的原理中,我们知道我们创建了一个对象,且当函数内部存在return且返回的是一个引用数据类型的时候,new的执行结果就是这个引用类型的数据,而this的绑定就是new创建出来的这个对象,所以我们打印出来new中创建对象的数据,下面是代码执行结果

43.png

箭头函数

1,箭头函数没有this,写在箭头函数中的this那也是它外层的非箭头函数的

js
代码解读
复制代码
function foo() { let bar = function () { let baz = () => { let fn = () => { console.log(this); } fn() } baz() } bar() } foo()

看这段代码,this写在fn箭头函数里面,那这个this属于谁呢,我们要知道箭头函数里面没有this,所以我们要一层一层往外判断首先fn是箭头函数,所以不是它的,然后是baz,baz也是箭头函数所以也不是baz的,然后是bar,bar不是箭头函数,所以this是属于bar函数的

2,箭头函数不能作为构造函数使用

js
代码解读
复制代码
let Foo = () => { this.name = '廖总' } let foo = new Foo()

在这段代码中,我们想得到一个对象foo,那我们能通过new关键字从箭头函数中来获得foo对象吗?看看代码运行结果

44.png 这里报错了,所以箭头函数是不能作为构造函数使用的。

call方法的实现原理

call方法可以直接将函数的this绑定在对象上,其实也是用了隐式绑定规则进行了非独立调用,将函数将 foo 引用到 obj 上,让 obj 调用foo,移除obj上的 foo,让我们来手搓一个效果一样的方法

js
代码解读
复制代码
function foo(x, y) { console.log(this.a); return x + y; } const obj = { a: 1 } Function.prototype.myCall = function (...args) { const context = args[0] const arg = args.slice(1) // [2, 3, 4] context.fn = this const res = context.fn(...arg) delete context.fn return res } let res = foo.myCall(obj, 2, 3, 4) console.log(res);

这段代码上我们在Function函数的原型上创建了一个myCall的方法形参...args表示将传入的实参以数组的方式使用,然后我们线拿到数组下标为0的对象,然后将剩下的内容分割出来然后我们用给传入对象也就是context添加一个fn属性,这个fn属性我们需要变为foo函数使对象能够调用这个函数,而在全局中myCall是由foo进行的隐式调用所以在myCall方法中,this表示的就是foo,我们将它添加到对象当中,然后让context 调用foo,我们知道在这里arg是分割后的数组,我们再用一下...arg可以将数组里的元素拆解出来,然后交给foo进行调用并将调用结果给res然后我们不能真的给obj对象中添加foo函数,所以要将其删除,最后将obj 调用foo的结果进行返回,所以最后foo.myCall(obj, 2, 3, 4)的效果与obj.foo(2, 3, 4)是一样的,我们来看看输出结果

45.png

输出结果我们们分析的预期是一样的

总结

this关键字在JavaScript中用于指代当前执行上下文的对象。通过使用this,可以简化对象内部方法的参数传递,使代码更加简洁和易于维护。this的绑定规则包括默认绑定、隐式绑定、显示绑定(call、apply、bind)和new绑定。箭头函数没有自己的this,而是继承外层函数的this。理解this的概念和绑定规则对于编写高效的JavaScript代码至关重要。

为什么要有this

我们看下面的代码例子

js
代码解读
复制代码
function identify(context) { return context.name.toUpperCase() } function speak(context) { var gretting = 'Hello,I am' + identify(context) console.log(gretting); } var me = { name: 'Tom' } speak(me)

在这段代码中,我们是想实现传参并将传入参数的字符全部变为大写,最后输出(Hello,I am(我们传入参数的大写))然后我们写了两个函数 speak,identify,在这里我们并没有调用this关键字,执行speak,将me对象传入speak对象中,然后调用对象的name属性,但是为了实现将属性的内容大写,我们又要使用到identify的函数,并要将对象me传入identify中,实现这个功能并返回,最后进行输出,下面是执行结果

34.png

但这样子的话,但凡我们需要添加一个新功能,就必须在所写的函数中进行传参,这样的话一个参数被传到几十个函数里,会导致十分混乱

让我们来使用this关键字优化一下

js
代码解读
复制代码
function identify() { return this.name.toUpperCase() } function speak() { var gretting = 'Hello,I am' + identify.call(this) console.log(gretting); } var me = { name: 'Tom' } speak.call(me)

可以看到,在两个函数中,我们并没有进行传参,而是用this代表了我们想传入的对象,看看执行结果是否和上面一样

35.png

可以看到运行结果是一样的,所以我们得出一个结论;this 让函数可以自动引用合适的上下文对象

this的概念

我们要先明白一些this的概念;this 是一个非常重要的关键字,它永远是一个代词,在js中永远代指某一个域,且this只在域中存在才有意义。 在全局作用域下它代指(在浏览器中是window,在Node.js中是global),下面是代码验证

36.png 可以看到this在全局下指向的是(在浏览器中是window,在Node.js中是global)

this的绑定规则

默认绑定

函数独立调用,this指向window

js
代码解读
复制代码
function foo(){ let person = { name: '彭于晏', age: 42 } console.log(this); } foo()

让我们来分析一下这段代码,在这段代码中,我们写了一个foo函数并执行,可以看到this关键字写在foo里面,属于foo函数,那这个this代指谁呢,我们来看看输出结果

37.png 可以看到这个this还是代指的(在浏览器中是window,在Node.js中是global),我们再看看下面的代码

js
代码解读
复制代码
function foo(){ let person = { name: '彭于晏', age: 42 } console.log(this); } function bar() { let person ={ name: '金城武', age:51 } foo() } bar()

这段代码中,我们又创建了一个bar函数并将foo函数放入bar函数中执行,将bar函数放入全局中执行,此时this关键字还是属于foo函数,但foo函数从在全局执行变成了在bar函数中执行,那此时this代指谁呢?我们来看看结果

38.png

可以看到,此时this代指的还是(在浏览器中是window,在Node.js中是global)

可以得出this的绑定和和所在函数的位置没有关系,当this所在函数独立调用的时候,它绑定的就是(在浏览器中是window,在Node.js中是global)。

隐式绑定

当函数的引用有上下文对象(当函数被某一个对象所拥有且调用)this指向该上下文对象

js
代码解读
复制代码
function foo(){ console.log(this); } const obj ={ a: 1, foo: foo } obj.foo()

在这段代码中我们创建了foo函数和obj对象,并在obj对象当中将foo函数添加进去了,最后在全局下调用obj对象并执行,那此时foo中的this绑定了谁呢

下面是代码的执行结果

39.png

可以看到此时this代表的就是调用函数foo的对象obj了

那当函数的引用有一连串上下文对象,this指向谁呢

js
代码解读
复制代码
function foo(){ console.log(this.a); } const obj ={ a: 1, foo: foo } const obj2 = { a: 2, obj: obj } obj2.obj.foo()

在这段代码中foo()属于obj,obj属于obj2,所以foo也属于obj,那此时foo函数中的this代指谁呢,这里只需遵守一个就近原则,那就是离函数近的那一个,下面是代码执行结果

40.png 我们可以得出结论;当函数的引用有一连串上下文对象,this指向最近的那个对象

显示绑定

调用call apply bind方法显示的将函数的this绑定到一个对象上 我们来看看实例

js
代码解读
复制代码
function foo() { console.log(this.a); } var obj = { a: 1 } foo()

在这段代码中,我们独立调用foo函数,因此foo中的this应该是指向全局,但是全局中没有a,因此打印出来的就是undefined,那我们想让this不用隐式绑定去绑定在obj对象上,可以怎么样呢

js
代码解读
复制代码
function foo() { console.log(this.a); } var obj = { a: 1 } foo.call(obj)

我们可以使用call方法强行将foo中的this指向obj,下面是运行结果

41.png

可以看到我们实现想要的效果了,this的指向被强行指向了obj

那如果函数foo需要接收参数呢

js
代码解读
复制代码
function foo(x,y) { console.log(this.a,x+y); } var obj = { a: 1 } foo.call(obj)

此时怎么给foo函数进行传参呢,要弄懂这个问题,我们要先知道foo是怎么被执行的,在这段代码中我们只是使用了call方法,并没有去人为触发foo函数,其实就是在call方法中帮我们触发了foo函数,所以本来是foo接受的参数call也会帮我们接收

js
代码解读
复制代码
function foo(x,y) { console.log(this.a,x+y); } var obj = { a: 1 } foo.call(obj,2,3)

看看结果是否正确

42.png

没有问题,结果正常输出了

除了call方法还有apply方法,它们俩的区别就是接收参数时call是零散的接收,而apply是通过数组去接收 foo.call(obj,2,3),foo.apply(obj,[2,3]),还有一个和call方法一样,只是需要函数体去接收 let bar=foo. bind(obj,2,3),然后再执行bar,我们也可以将参数传入接收的函数体中let bar=foo. bind(obj),bar(2,3)

new绑定

提到new,我们可以先了解一下new的原理下面的文章有进行讲解 juejin.cn/post/743932…

js
代码解读
复制代码
function Person() { this.name = '彭于晏', this.age = 42 } let p = new Person() console.log(p);

在这段代码中this的指向是谁呢,在new的原理中,我们知道我们创建了一个对象,且当函数内部存在return且返回的是一个引用数据类型的时候,new的执行结果就是这个引用类型的数据,而this的绑定就是new创建出来的这个对象,所以我们打印出来new中创建对象的数据,下面是代码执行结果

43.png

箭头函数

1,箭头函数没有this,写在箭头函数中的this那也是它外层的非箭头函数的

js
代码解读
复制代码
function foo() { let bar = function () { let baz = () => { let fn = () => { console.log(this); } fn() } baz() } bar() } foo()

看这段代码,this写在fn箭头函数里面,那这个this属于谁呢,我们要知道箭头函数里面没有this,所以我们要一层一层往外判断首先fn是箭头函数,所以不是它的,然后是baz,baz也是箭头函数所以也不是baz的,然后是bar,bar不是箭头函数,所以this是属于bar函数的

2,箭头函数不能作为构造函数使用

js
代码解读
复制代码
let Foo = () => { this.name = '廖总' } let foo = new Foo()

在这段代码中,我们想得到一个对象foo,那我们能通过new关键字从箭头函数中来获得foo对象吗?看看代码运行结果

44.png 这里报错了,所以箭头函数是不能作为构造函数使用的。

call方法的实现原理

call方法可以直接将函数的this绑定在对象上,其实也是用了隐式绑定规则进行了非独立调用,将函数将 foo 引用到 obj 上,让 obj 调用foo,移除obj上的 foo,让我们来手搓一个效果一样的方法

js
代码解读
复制代码
function foo(x, y) { console.log(this.a); return x + y; } const obj = { a: 1 } Function.prototype.myCall = function (...args) { const context = args[0] const arg = args.slice(1) // [2, 3, 4] context.fn = this const res = context.fn(...arg) delete context.fn return res } let res = foo.myCall(obj, 2, 3, 4) console.log(res);

这段代码上我们在Function函数的原型上创建了一个myCall的方法形参...args表示将传入的实参以数组的方式使用,然后我们线拿到数组下标为0的对象,然后将剩下的内容分割出来然后我们用给传入对象也就是context添加一个fn属性,这个fn属性我们需要变为foo函数使对象能够调用这个函数,而在全局中myCall是由foo进行的隐式调用所以在myCall方法中,this表示的就是foo,我们将它添加到对象当中,然后让context 调用foo,我们知道在这里arg是分割后的数组,我们再用一下...arg可以将数组里的元素拆解出来,然后交给foo进行调用并将调用结果给res然后我们不能真的给obj对象中添加foo函数,所以要将其删除,最后将obj 调用foo的结果进行返回,所以最后foo.myCall(obj, 2, 3, 4)的效果与obj.foo(2, 3, 4)是一样的,我们来看看输出结果

45.png

输出结果我们们分析的预期是一样的

总结

this关键字在JavaScript中用于指代当前执行上下文的对象。通过使用this,可以简化对象内部方法的参数传递,使代码更加简洁和易于维护。this的绑定规则包括默认绑定、隐式绑定、显示绑定(call、apply、bind)和new绑定。箭头函数没有自己的this,而是继承外层函数的this。理解this的概念和绑定规则对于编写高效的JavaScript代码至关重要。

为什么要有this

我们看下面的代码例子

js
代码解读
复制代码
function identify(context) { return context.name.toUpperCase() } function speak(context) { var gretting = 'Hello,I am' + identify(context) console.log(gretting); } var me = { name: 'Tom' } speak(me)

在这段代码中,我们是想实现传参并将传入参数的字符全部变为大写,最后输出(Hello,I am(我们传入参数的大写))然后我们写了两个函数 speak,identify,在这里我们并没有调用this关键字,执行speak,将me对象传入speak对象中,然后调用对象的name属性,但是为了实现将属性的内容大写,我们又要使用到identify的函数,并要将对象me传入identify中,实现这个功能并返回,最后进行输出,下面是执行结果

34.png

但这样子的话,但凡我们需要添加一个新功能,就必须在所写的函数中进行传参,这样的话一个参数被传到几十个函数里,会导致十分混乱

让我们来使用this关键字优化一下

js
代码解读
复制代码
function identify() { return this.name.toUpperCase() } function speak() { var gretting = 'Hello,I am' + identify.call(this) console.log(gretting); } var me = { name: 'Tom' } speak.call(me)

可以看到,在两个函数中,我们并没有进行传参,而是用this代表了我们想传入的对象,看看执行结果是否和上面一样

35.png

可以看到运行结果是一样的,所以我们得出一个结论;this 让函数可以自动引用合适的上下文对象

this的概念

我们要先明白一些this的概念;this 是一个非常重要的关键字,它永远是一个代词,在js中永远代指某一个域,且this只在域中存在才有意义。 在全局作用域下它代指(在浏览器中是window,在Node.js中是global),下面是代码验证

36.png 可以看到this在全局下指向的是(在浏览器中是window,在Node.js中是global)

this的绑定规则

默认绑定

函数独立调用,this指向window

js
代码解读
复制代码
function foo(){ let person = { name: '彭于晏', age: 42 } console.log(this); } foo()

让我们来分析一下这段代码,在这段代码中,我们写了一个foo函数并执行,可以看到this关键字写在foo里面,属于foo函数,那这个this代指谁呢,我们来看看输出结果

37.png 可以看到这个this还是代指的(在浏览器中是window,在Node.js中是global),我们再看看下面的代码

js
代码解读
复制代码
function foo(){ let person = { name: '彭于晏', age: 42 } console.log(this); } function bar() { let person ={ name: '金城武', age:51 } foo() } bar()

这段代码中,我们又创建了一个bar函数并将foo函数放入bar函数中执行,将bar函数放入全局中执行,此时this关键字还是属于foo函数,但foo函数从在全局执行变成了在bar函数中执行,那此时this代指谁呢?我们来看看结果

38.png

可以看到,此时this代指的还是(在浏览器中是window,在Node.js中是global)

可以得出this的绑定和和所在函数的位置没有关系,当this所在函数独立调用的时候,它绑定的就是(在浏览器中是window,在Node.js中是global)。

隐式绑定

当函数的引用有上下文对象(当函数被某一个对象所拥有且调用)this指向该上下文对象

js
代码解读
复制代码
function foo(){ console.log(this); } const obj ={ a: 1, foo: foo } obj.foo()

在这段代码中我们创建了foo函数和obj对象,并在obj对象当中将foo函数添加进去了,最后在全局下调用obj对象并执行,那此时foo中的this绑定了谁呢

下面是代码的执行结果

39.png

可以看到此时this代表的就是调用函数foo的对象obj了

那当函数的引用有一连串上下文对象,this指向谁呢

js
代码解读
复制代码
function foo(){ console.log(this.a); } const obj ={ a: 1, foo: foo } const obj2 = { a: 2, obj: obj } obj2.obj.foo()

在这段代码中foo()属于obj,obj属于obj2,所以foo也属于obj,那此时foo函数中的this代指谁呢,这里只需遵守一个就近原则,那就是离函数近的那一个,下面是代码执行结果

40.png 我们可以得出结论;当函数的引用有一连串上下文对象,this指向最近的那个对象

显示绑定

调用call apply bind方法显示的将函数的this绑定到一个对象上 我们来看看实例

js
代码解读
复制代码
function foo() { console.log(this.a); } var obj = { a: 1 } foo()

在这段代码中,我们独立调用foo函数,因此foo中的this应该是指向全局,但是全局中没有a,因此打印出来的就是undefined,那我们想让this不用隐式绑定去绑定在obj对象上,可以怎么样呢

js
代码解读
复制代码
function foo() { console.log(this.a); } var obj = { a: 1 } foo.call(obj)

我们可以使用call方法强行将foo中的this指向obj,下面是运行结果

41.png

可以看到我们实现想要的效果了,this的指向被强行指向了obj

那如果函数foo需要接收参数呢

js
代码解读
复制代码
function foo(x,y) { console.log(this.a,x+y); } var obj = { a: 1 } foo.call(obj)

此时怎么给foo函数进行传参呢,要弄懂这个问题,我们要先知道foo是怎么被执行的,在这段代码中我们只是使用了call方法,并没有去人为触发foo函数,其实就是在call方法中帮我们触发了foo函数,所以本来是foo接受的参数call也会帮我们接收

js
代码解读
复制代码
function foo(x,y) { console.log(this.a,x+y); } var obj = { a: 1 } foo.call(obj,2,3)

看看结果是否正确

42.png

没有问题,结果正常输出了

除了call方法还有apply方法,它们俩的区别就是接收参数时call是零散的接收,而apply是通过数组去接收 foo.call(obj,2,3),foo.apply(obj,[2,3]),还有一个和call方法一样,只是需要函数体去接收 let bar=foo. bind(obj,2,3),然后再执行bar,我们也可以将参数传入接收的函数体中let bar=foo. bind(obj),bar(2,3)

new绑定

提到new,我们可以先了解一下new的原理下面的文章有进行讲解 juejin.cn/post/743932…

js
代码解读
复制代码
function Person() { this.name = '彭于晏', this.age = 42 } let p = new Person() console.log(p);

在这段代码中this的指向是谁呢,在new的原理中,我们知道我们创建了一个对象,且当函数内部存在return且返回的是一个引用数据类型的时候,new的执行结果就是这个引用类型的数据,而this的绑定就是new创建出来的这个对象,所以我们打印出来new中创建对象的数据,下面是代码执行结果

43.png

箭头函数

1,箭头函数没有this,写在箭头函数中的this那也是它外层的非箭头函数的

js
代码解读
复制代码
function foo() { let bar = function () { let baz = () => { let fn = () => { console.log(this); } fn() } baz() } bar() } foo()

看这段代码,this写在fn箭头函数里面,那这个this属于谁呢,我们要知道箭头函数里面没有this,所以我们要一层一层往外判断首先fn是箭头函数,所以不是它的,然后是baz,baz也是箭头函数所以也不是baz的,然后是bar,bar不是箭头函数,所以this是属于bar函数的

2,箭头函数不能作为构造函数使用

js
代码解读
复制代码
let Foo = () => { this.name = '廖总' } let foo = new Foo()

在这段代码中,我们想得到一个对象foo,那我们能通过new关键字从箭头函数中来获得foo对象吗?看看代码运行结果

44.png 这里报错了,所以箭头函数是不能作为构造函数使用的。

call方法的实现原理

call方法可以直接将函数的this绑定在对象上,其实也是用了隐式绑定规则进行了非独立调用,将函数将 foo 引用到 obj 上,让 obj 调用foo,移除obj上的 foo,让我们来手搓一个效果一样的方法

js
代码解读
复制代码
function foo(x, y) { console.log(this.a); return x + y; } const obj = { a: 1 } Function.prototype.myCall = function (...args) { const context = args[0] const arg = args.slice(1) // [2, 3, 4] context.fn = this const res = context.fn(...arg) delete context.fn return res } let res = foo.myCall(obj, 2, 3, 4) console.log(res);

这段代码上我们在Function函数的原型上创建了一个myCall的方法形参...args表示将传入的实参以数组的方式使用,然后我们线拿到数组下标为0的对象,然后将剩下的内容分割出来然后我们用给传入对象也就是context添加一个fn属性,这个fn属性我们需要变为foo函数使对象能够调用这个函数,而在全局中myCall是由foo进行的隐式调用所以在myCall方法中,this表示的就是foo,我们将它添加到对象当中,然后让context 调用foo,我们知道在这里arg是分割后的数组,我们再用一下...arg可以将数组里的元素拆解出来,然后交给foo进行调用并将调用结果给res然后我们不能真的给obj对象中添加foo函数,所以要将其删除,最后将obj 调用foo的结果进行返回,所以最后foo.myCall(obj, 2, 3, 4)的效果与obj.foo(2, 3, 4)是一样的,我们来看看输出结果

45.png

输出结果我们们分析的预期是一样的

总结

this关键字在JavaScript中用于指代当前执行上下文的对象。通过使用this,可以简化对象内部方法的参数传递,使代码更加简洁和易于维护。this的绑定规则包括默认绑定、隐式绑定、显示绑定(call、apply、bind)和new绑定。箭头函数没有自己的this,而是继承外层函数的this。理解this的概念和绑定规则对于编写高效的JavaScript代码至关重要。

注:本文转载自juejin.cn的竺梓君的文章"https://juejin.cn/post/7440079782919929907"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top