热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

什么是js中的this,它与Java中的this有什么区别?

关于Java中this的用法参见https:blog.csdn.netqq_21225505articledetails88017889js中this的七种使用场景this一般

关于Java中this的用法参见https://blog.csdn.net/qq_21225505/article/details/88017889

js 中this 的七种使用场景

this一般在函数内部使用,表示该函数所处的环境对象,只有在函数运行的时候才能被确定,不同的调用方式所对应的this值是不同的。

情况一:全局 & 调用普通函数

在全局环境中,this 永远指向 window。

console.log(this === window); //true

普通函数在调用时候(注意不是构造函数,前面不加 new),其中的 this 也是指向 window。

var x = 10;
function foo(){console.log(this); //Windowconsole.log(this.x); //10
}
foo();

情况二:构造函数

所谓的构造函数就是由一个函数 new 出来的对象,this就指向新对象,一般构造函数的函数名首字母大写,例如像 Object,Function,Array 这些都属于构造函数。

上述代码,如果函数作为构造函数使用,那么其中的 this 就代表它即将 new 出来的对象。

但是如果直接调用 Foo 函数,而不是 new Foo(),那就变成情况1,这时候 Foo() 就变成普通函数。

function Foo(){this.x = 10;console.log(this); //Window
}
var foo = Foo();

情况三:对象方法

如果函数作为对象的方法时,方法中的 this 指向该对象。

var obj = {x: 10,foo: function () {console.log(this); //Objectconsole.log(this.x); //10}
};
obj.foo();

注意:若是在对象方法中定义函数,那么情况就不同了。

var obj = {x: 10,foo: function () {function f(){console.log(this); //Windowconsole.log(this.x); //undefined}f();}
}
obj.foo();

可以这么理解:函数 f 虽然是在 obj.foo 内部定义的,但它仍然属于一个普通函数,this 仍指向 window。

在这里,如果想要调用上层作用域中的变量 obj.x,可以使用 self 缓存外部 this 变量。

var obj = {x: 10,foo: function () {var self = this;function f(){console.log(self); //{x: 10}console.log(self.x); //10}f();}
}
obj.foo();

如果 foo 函数不作为对象方法被调用:

var obj = {x: 10,foo: function () {console.log(this); //Windowconsole.log(this.x); //undefined}
};
var fn = obj.foo;
fn();

obj.foo 被赋值给一个全局变量,并没有作为 obj 的一个属性被调用,那么此时 this 的值是 window。

情况四:构造函数 prototype 属性

function Foo(){this.x = 10;
}
Foo.prototype.getX = function () {console.log(this); //Foo {x: 10, getX: function}console.log(this.x); //10
}
var foo = new Foo();
foo.getX();

在 Foo.prototype.getX 函数中,this 指向的 foo 对象。不仅仅如此,即便是在整个原型链中,this 代表的也是当前对象的值。

情况五:函数用 call、apply或者 bind 调用。

var obj = {x: 10
}
function foo(){console.log(this); //{x: 10}console.log(this.x); //10
}
foo.call(obj);
foo.apply(obj);
foo.bind(obj)();

当一个函数被 call、apply 或者 bind 调用时,this 的值就取传入的对象的值。

情况六:DOM event this

在一个 HTML DOM 事件处理程序里,this 始终指向这个处理程序所绑定的 HTML DOM 节点:

function Listener(){ document.getElementById('foo').addEventListener('click', this.handleClick); //这里的 this 指向 Listener 这个对象。不是强调的是这里的 this
}
Listener.prototype.handleClick = function (event) {console.log(this); //


}
var listener = new Listener();
document.getElementById('foo').click();

这个很好理解,就相当于是给函数传参,使 handleClick 运行时上下文改变了,相当于下面这样的代码:

var obj = {x: 10,fn: function() {console.log(this); //Windowconsole.log(this.x); //undefined}
};
function foo(fn) {fn();
}
foo(obj.fn);

你也可以用通过 bind 切换上下文:

function Listener(){document.getElementById('foo').addEventListener('click',this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {console.log(this); //Listener {}
}
var listener = new Listener();
document.getElementById('foo').click();

前六种情况其实可以总结为: this 指向调用该方法的对象。

情况七:箭头函数中的 this

当使用箭头函数的时候,情况就有所不同了:箭头函数内部的 this 是词法作用域,由上下文确定。

var obj = {x: 10,foo: function() {var fn = () => {return () => {return () => {console.log(this); //Object {x: 10}console.log(this.x); //10}}}fn()()();}
}
obj.foo();

现在,箭头函数完全修复了 this 的指向,this 总是指向词法作用域,也就是外层调用者 obj。

如果使用箭头函数,以前的这种 hack 写法:

var self = this;

 就不再需要了。

var obj = {x: 10,foo: function() {var fn = () => {return () => {return () => {console.log(this); // Object {x: 10}console.log(this.x); //10}}}fn.bind({x: 14})()()();fn.call({x: 14})()();}
}
obj.foo();

由于 this 在箭头函数中已经按照词法作用域绑定了,所以,用 call()或者 apply()调用箭头函数时,无法对 this 进行绑定,即传入的第一个参数被忽略。

 

JS如何改变this的值

第一种: new关键字改变this指向

//构造函数版this
function Fn(){this.user = "追梦子";
}
var a = new Fn();
console.log(a.user); //追梦子

用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象a中会有user,因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份

第二种: call()     fun.call(this的值,参数列表)

var a = {user:"追梦子",fn:function(){console.log(this.user); //追梦子}
}
var b = a.fn;
b.call(a); //若不用call,则b()执行后this指的是Window对象

把b添加到第一个参数的环境中,简单来说,this就会指向那个对象。

call方法除了第一个参数以外还可以添加多个参数,如下:

var a = {user:"追梦子",fn:function(e,ee){console.log(this.user); //追梦子console.log(e+ee); //3}
}
var b = a.fn;
b.call(a,1,2);

第三种:apply()          fun.apply(this的值,参数数组)

var a = {user:"追梦子",fn:function(){console.log(this.user); //追梦子}
}
var b = a.fn;
b.apply(a);

apply方法和call方法有些相似,它也可以改变this的指向,也可以有多个参数,但是不同的是,第二个参数必须是一个数组,如下:

var a = {user:"追梦子",fn:function(e,ee){console.log(this.user); //追梦子console.log(e+ee); //11}
}
var b = a.fn;
b.apply(a,[10,1]);

//注意如果call和apply的第一个参数写的是null,那么this指向的是window对象
var a = {user:"追梦子",fn:function(){console.log(this); //Window {external: Object, chrome: Object, document: document, a: Object, speechSynthesis: SpeechSynthesis…}}
}
var b = a.fn;
b.apply(null);

第四种:bind()          fun.bind(this的值,参数列表)

bind方法和call、apply方法有些不同,如下:

var a = {user:"追梦子",fn:function(){console.log(this.user);}
}
var b = a.fn;
b.bind(a); //代码没有被打印

我们发现代码没有被打印,对,这就是bind和call、apply方法的不同,实际上bind方法返回的是一个修改过后的函数供后续调用。

var a = {user:"追梦子",fn:function(){console.log(this.user);}
}
var b = a.fn;
var c = b.bind(a);
console.log(c); //function() { [native code] }

函数c看看,能不能打印出对象a里面的user

var a = {user:"追梦子",fn:function(){console.log(this.user); //追梦子}
}
var b = a.fn;
var c = b.bind(a);
c();

同样bind也可以有多个参数,并且参数可以执行的时候再次添加,但是要注意的是,后续调用新函数时的实参要往已有参数的后面排,参数是按照形参的顺序进行的。

var a = {user:"追梦子",fn:function(e,d,f){console.log(this.user); //追梦子console.log(e,d,f); //10 1 2}
}
var b = a.fn;
var c = b.bind(a,10);
c(1,2);

总结: call和apply都是改变上下文中的this并立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加,这是它们的区别

以上转自https://blog.csdn.net/weixin_40387601/article/details/80313884

 


推荐阅读
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • 本文介绍了获取关联数组键的列表的方法,即使用Object.keys()函数。同时还提到了该方法在不同浏览器的支持情况,并附上了一个代码片段供读者参考。 ... [详细]
  • 本文记录了在vue cli 3.x中移除console的一些采坑经验,通过使用uglifyjs-webpack-plugin插件,在vue.config.js中进行相关配置,包括设置minimizer、UglifyJsPlugin和compress等参数,最终成功移除了console。同时,还包括了一些可能出现的报错情况和解决方法。 ... [详细]
  • 本文介绍了一个React Native新手在尝试将数据发布到服务器时遇到的问题,以及他的React Native代码和服务器端代码。他使用fetch方法将数据发送到服务器,但无法在服务器端读取/获取发布的数据。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
author-avatar
jajajaja幸福_348
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有