this有哪些使用场景?跟C,Java中的this有什么区别?如何改变this的值?
2018-06-19 06:46
633 查看
(转自薛跳跳的博客)
this 的七种使用场景
this一般在函数内部使用,表示该函数所处的环境对象,只有在函数运行的时候才能被确定,不同的调用方式所对应的this值是不同的。
情况一:全局 & 调用普通函数
在全局环境中,this 永远指向 window。
console.log(this === window); //true
var x = 10; function foo(){ console.log(this); //Window console.log(this.x); //10 } foo();
情况二:构造函数
所谓的构造函数就是由一个函数 new 出来的对象,this就指向新对象,一般构造函数的函数名首字母大写,例如像 Object,Function,Array 这些都属于构造函数。function Foo(){ this.x = 10; console.log(this); //Foo {x:10} } var foo = new Foo(); console.log(foo.x); //10上述代码,如果函数作为构造函数使用,那么其中的 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); //Object console.log(this.x); //10 } }; obj.foo();注意:若是在对象方法中定义函数,那么情况就不同了。
var obj = { x: 10, foo: function () { function f(){ console.log(this); //Window console.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); //Window console.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); //<div id="foo"></div> } var listener = new Listener(); document.getElementById('foo').click();这个很好理解,就相当于是给函数传参,使 handleClick 运行时上下文改变了,相当于下面这样的代码:
var obj = { x: 10, fn: function() { console.log(this); //Window console.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 进行绑定,即传入的第一个参数被忽略。
如何改变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方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加,这是它们的区别 阅读更多
相关文章推荐
- this有哪些使用场景?跟C,Java中的this有什么区别?如何改变this的值?
- AsyncTask使用在哪些场景?它的缺陷是什么?如何解决?
- volatile、synchronized、lock有什么区别,以及在哪些场景下使用哪种方式?
- 什么是静态代码块?java中如何使用空参构造方法自动生成不同名字的对象,使用非静态的属性和静态属性有什么区别,原因是什么?如何理解static关键字
- AsyncTask使用在哪些场景?它的缺陷是什么?如何解决?
- 什么是沙盒(sandbox)?沙盒包含哪些文件,描述每个文件的使用场景。如何获取这些文件的路径?如何获取应用程序包中文件的路径?
- volatile、synchronized、lock有什么区别,以及在哪些场景下使用哪种方式?
- java 如何使用SpringMVC 和struts2有什么区别
- 你如何理解 HTML5 的 section?会在什么场景使用?为什么这些场景使用 section 而不是 div?
- java this 使用场景
- [Java]_[初级]_[比较String和StringBuffer的区别和使用场景]
- java-测试synchronized使用xxx.class和this使用的区别
- 深拷贝和浅拷贝的区别是什么?你会如何使用它们?
- 类(class)和结构(struct)的区别是什么?它们对性能有影响吗?.NET BCL里有哪些是类(结构),为什么它们不是结构(类)?在自定义类型时,您如何选择是类还是结构?
- 在JSP中调用JAVA类和使用JavaBean有什么区别?
- (转)在JSP中调用JAVA类和使用JavaBean有什么区别?
- Java第二课 Java面向对象编程,面向对象编程和面向过程编程的区别,我们如何才能掌握面向对象的编程,类和对象的关系;讲解了Java中的构造、重载、this和super变量、静态变量、Java中的常
- 自旋锁与信号量的区别是什么? 分别在什么场景下使用?
- java中什么是内部类?它有什么用?如何使用?
- Java 关键字super和this的使用及区别