关于this的全面解析(call,apply,new)

我们在写代码的时候,时常会被this弄的傻傻分不清楚,看源码的时候也经常被call啊apply啊弄的头皮发麻。this到底是什么?本文主要根据书上和实际应用做了一些归纳。一般情况下this有4种绑定规则: 1、默认绑定 - this指向全局变量 举例: function baz(){ console.log('a',this.a); }; var a = 2; baz(); // a 2 在非严格模式下,我们调用了baz,它没有被任何对象包裹,而是暴露在全局环境中,因此此时它被调用的上下文就是全局环境,所以获取到this.a是2; 2、隐式绑定 这种情况应该是最常见的,我们调用的方法被包含在某个对象中,此时应该找到调用这个方法的对象所处的上下文。 举例: function baz(){ console.log('a',this.a); }; var a = 2; var obj = { a: 3, baz: baz } obj.baz(); // a, 3 这个时候,this指向调用baz这个方法的对象obj;所以获取的this.a就是obj.a是3; 思考一下下面的this.a的值又是什么: function baz(){ console.log('a',this.a); }; var a = 2; var obj = { a: 3, baz: baz }; var obj2 = { a: 4, baz: obj.baz } obj2.baz(); tips: 对象属性的引用链只有最后一层在调用位置中起作用。 3、显式绑定 这里就是函数可以使用的方法call(obj,param1,param2,...)和apply(obj,[param1,param2,...]),它们的作用是我们可以显式的改变函数的上下文(this),参数说明: obj:一个对象,将方法的this指向该对象的this; paramX:参数,两者的表现形式不同 var a = 2; function baz(){ console.log('a',this.a); }; var obj = { a: 3 }; baz.call(obj); // 改变了this,并执行了函数 // a 3 如果直接baz(),则采用的是第一种规则,这里使用baz.call强行将baz的this指向了obj,所以此时baz中的this是obj; 应用场景:带参数的 var a = 2; function baz(p1, p2) { console.log(this.a, p1, p2); }; var obj = { a: 3 }; var foo = function () { return baz.apply(obj, arguments) }; foo("hi,", "heimayu"); // 3 hi, heimayu 4、new绑定 在js中,我们经常使用new来对函数进行构造调用,如下: function Foo(a) { this.a = a; }; var foo = new Foo(3); console.log("a", foo.a) 这里,使用new Foo()的时候构造出一个新的对象foo并把它绑定到Foo调用中的this上。 5、优先级 在大多数情况下我们找到函数的调用位置,并判断应用哪种规则,就可以快速找到this;结论: new绑定 > 显式绑定(call,apply) > 隐式绑定 > 全局默认绑定 6、一些例外 规则是死的,程序是活的,总有例外出现。比如啊: 我不关心this是什么 function foo(a, b) { console.log("a:" + a, "b:" + b); }; foo.apply(null, [1, 2]); // a:1 b:2 ES6箭头函数 箭头函数不使用上面的规则,而是根据 由外层的作用域来决定它的this function foo() { // return function () { // console.log('第一种情况', this.a) // } return (a)=>{ console.log('第二种情况',this.a) } }; var obj1 = { a: 2 }; var obj2 = { a: 3 }; var bar = foo.call(obj1); bar.call(obj2); // 第一种情况:3 // 第二种情况:2 记住箭头函数的绑定无法被修改!!!因此在执行bar的时调用了foo,而foo中的this是指向到obj1的。 最常见的场景: var a = 1; var obj = { a:2, foo: function(){ setTimeout(function(){ console.log(this.a) },100) } }; obj.foo(); // 1 在ES5中,我们想打出的值是2,会这样做: var a = 1; var obj = { a:2, foo: function(){ let self = this; setTimeout(function(){ console.log(self.a) },100) } }; obj.foo(); 在ES6中,则可以直接这样: var a = 1; var obj = { a:2, foo: function(){ setTimeout(()=>{ console.log(this.a) },100) } }; obj.foo(); 理解一下:因为箭头函数中的this,指向了foo,foo的上下文是obj。具体的说:箭头函数会继承外层函数调用的this绑定。https://www.cnblogs.com/webhmy/p/10212597.html
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信