为什么要有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
中,实现这个功能并返回,最后进行输出,下面是执行结果
但这样子的话,但凡我们需要添加一个新功能,就必须在所写的函数中进行传参,这样的话一个参数被传到几十个函数里,会导致十分混乱
让我们来使用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
代表了我们想传入的对象,看看执行结果是否和上面一样
可以看到运行结果是一样的,所以我们得出一个结论;this
让函数可以自动引用合适的上下文对象
this的概念
我们要先明白一些this
的概念;this
是一个非常重要的关键字,它永远是一个代词,在js
中永远代指某一个域,且this
只在域中存在才有意义。
在全局作用域下它代指(在浏览器中是window,在Node.js中是global),下面是代码验证
可以看到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
代指谁呢,我们来看看输出结果
可以看到这个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
代指谁呢?我们来看看结果
可以看到,此时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
绑定了谁呢
下面是代码的执行结果
可以看到此时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
代指谁呢,这里只需遵守一个就近原则,那就是离函数近的那一个,下面是代码执行结果
我们可以得出结论;当函数的引用有一连串上下文对象,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
,下面是运行结果
可以看到我们实现想要的效果了,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)
看看结果是否正确
没有问题,结果正常输出了
除了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
中创建对象的数据,下面是代码执行结果
箭头函数
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
对象吗?看看代码运行结果
这里报错了,所以箭头函数是不能作为构造函数使用的。
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)
是一样的,我们来看看输出结果
输出结果我们们分析的预期是一样的
总结
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
中,实现这个功能并返回,最后进行输出,下面是执行结果
但这样子的话,但凡我们需要添加一个新功能,就必须在所写的函数中进行传参,这样的话一个参数被传到几十个函数里,会导致十分混乱
让我们来使用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
代表了我们想传入的对象,看看执行结果是否和上面一样
可以看到运行结果是一样的,所以我们得出一个结论;this
让函数可以自动引用合适的上下文对象
this的概念
我们要先明白一些this
的概念;this
是一个非常重要的关键字,它永远是一个代词,在js
中永远代指某一个域,且this
只在域中存在才有意义。
在全局作用域下它代指(在浏览器中是window,在Node.js中是global),下面是代码验证
可以看到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
代指谁呢,我们来看看输出结果
可以看到这个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
代指谁呢?我们来看看结果
可以看到,此时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
绑定了谁呢
下面是代码的执行结果
可以看到此时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
代指谁呢,这里只需遵守一个就近原则,那就是离函数近的那一个,下面是代码执行结果
我们可以得出结论;当函数的引用有一连串上下文对象,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
,下面是运行结果
可以看到我们实现想要的效果了,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)
看看结果是否正确
没有问题,结果正常输出了
除了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
中创建对象的数据,下面是代码执行结果
箭头函数
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
对象吗?看看代码运行结果
这里报错了,所以箭头函数是不能作为构造函数使用的。
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)
是一样的,我们来看看输出结果
输出结果我们们分析的预期是一样的
总结
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
中,实现这个功能并返回,最后进行输出,下面是执行结果
但这样子的话,但凡我们需要添加一个新功能,就必须在所写的函数中进行传参,这样的话一个参数被传到几十个函数里,会导致十分混乱
让我们来使用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
代表了我们想传入的对象,看看执行结果是否和上面一样
可以看到运行结果是一样的,所以我们得出一个结论;this
让函数可以自动引用合适的上下文对象
this的概念
我们要先明白一些this
的概念;this
是一个非常重要的关键字,它永远是一个代词,在js
中永远代指某一个域,且this
只在域中存在才有意义。
在全局作用域下它代指(在浏览器中是window,在Node.js中是global),下面是代码验证
可以看到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
代指谁呢,我们来看看输出结果
可以看到这个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
代指谁呢?我们来看看结果
可以看到,此时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
绑定了谁呢
下面是代码的执行结果
可以看到此时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
代指谁呢,这里只需遵守一个就近原则,那就是离函数近的那一个,下面是代码执行结果
我们可以得出结论;当函数的引用有一连串上下文对象,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
,下面是运行结果
可以看到我们实现想要的效果了,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)
看看结果是否正确
没有问题,结果正常输出了
除了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
中创建对象的数据,下面是代码执行结果
箭头函数
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
对象吗?看看代码运行结果
这里报错了,所以箭头函数是不能作为构造函数使用的。
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)
是一样的,我们来看看输出结果
输出结果我们们分析的预期是一样的
总结
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
中,实现这个功能并返回,最后进行输出,下面是执行结果
但这样子的话,但凡我们需要添加一个新功能,就必须在所写的函数中进行传参,这样的话一个参数被传到几十个函数里,会导致十分混乱
让我们来使用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
代表了我们想传入的对象,看看执行结果是否和上面一样
可以看到运行结果是一样的,所以我们得出一个结论;this
让函数可以自动引用合适的上下文对象
this的概念
我们要先明白一些this
的概念;this
是一个非常重要的关键字,它永远是一个代词,在js
中永远代指某一个域,且this
只在域中存在才有意义。
在全局作用域下它代指(在浏览器中是window,在Node.js中是global),下面是代码验证
可以看到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
代指谁呢,我们来看看输出结果
可以看到这个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
代指谁呢?我们来看看结果
可以看到,此时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
绑定了谁呢
下面是代码的执行结果
可以看到此时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
代指谁呢,这里只需遵守一个就近原则,那就是离函数近的那一个,下面是代码执行结果
我们可以得出结论;当函数的引用有一连串上下文对象,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
,下面是运行结果
可以看到我们实现想要的效果了,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)
看看结果是否正确
没有问题,结果正常输出了
除了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
中创建对象的数据,下面是代码执行结果
箭头函数
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
对象吗?看看代码运行结果
这里报错了,所以箭头函数是不能作为构造函数使用的。
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)
是一样的,我们来看看输出结果
输出结果我们们分析的预期是一样的
总结
this
关键字在JavaScript
中用于指代当前执行上下文的对象。通过使用this
,可以简化对象内部方法的参数传递,使代码更加简洁和易于维护。this
的绑定规则包括默认绑定、隐式绑定、显示绑定(call
、apply
、bind
)和new
绑定。箭头函数没有自己的this
,而是继承外层函数的this
。理解this
的概念和绑定规则对于编写高效的JavaScript
代码至关重要。
评论记录:
回复评论: