JavaScript中的this指向问题
在JS中,this属于一个关键字,也就是可以理解为,它是一个系统自带命令通常,我们把它的含义解释为:当前对象
-
语法
this
-
值
当前执行代码的环境对象
-
那么问题来了: 当前对象到底是指谁呢?
-
全局环境
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)
this
都指向全局对象。// 在浏览器中, window 对象同时也是全局对象: console.log(this === window); // true a = 37; console.log(window.a); // 37 this.b = "MDN"; console.log(window.b) // "MDN" console.log(b) // "MDN"
-
函数(运行内)环境
在函数内部,
this
的值取决于函数被调用的方式。 -
简单调用
-
因为下面的代码不在严格模式下,且
this
的值不是由该调用设置的,所以this
的值默认指向全局对象。function f1(){ return this; } //在浏览器中: f1() === window; //在浏览器中,全局对象是window
然而,在严格模式下,
this
将保持他进入执行环境时的值,所以下面的this
将会默认为undefined
。function f2(){ "use strict"; // 这里是严格模式 return this; } f2() === undefined; // true
所以,在严格模式下,如果
this
没有被执行环境(execution context)定义,那它将保持为undefined
。
-
-
如果要想把
this
的值从一个环境传到另一个,就要用call
或者apply
方法。var obj = {a: 1}; var a = 2; function whatsThis(arg) { return this.a; // this的值取决于函数的调用方式 } whatsThis(); // 2 whatsThis.call(obj); // 1 whatsThis.apply(obj); // 1
-
当一个函数在其主体中使用
this
关键字时,可以通过使用函数继承自Function.prototype
的call
或apply
方法将this
值绑定到调用中的特定对象。function add(c, d) { return this.a + this.b + c + d; } var arr = {a: 1, b: 3}; // 第一个参数是作为‘this’使用的对象 // 后续参数作为参数传递给函数调用 add.call(arr, 5, 7); // 1 + 3 + 5 + 7 = 16 // 第一个参数也是作为‘this’使用的对象 // 第二个参数是一个数组,数组里的元素用作函数调用中的参数 add.apply(arr, [10, 20]); // 1 + 3 + 10 + 20 = 34
-
bind
方法- ECMAScript 5 引入了
Function.prototype.bind
。调用f.bind(someObject)
会创建一个与f
具有相同函数体和作用域的函数,但是在这个新函数中,this
将永久地被绑定到了bind
的第一个参数,无论这个函数是如何被调用的。function f(){ return this.a; } var g = f.bind({a:"azerty"}); console.log(g()); // azerty var h = g.bind({a:'yoo'}); // bind只生效一次! console.log(h()); // azerty var o = {a:37, f:f, g:g, h:h}; console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
- ECMAScript 5 引入了
-
箭头函数
-
在[箭头函数]中,
this
与封闭词法环境的this
保持一致。在全局代码中,它将被设置为全局对象:var obj = { show :function(){ setTimeout(() => { console.log(this) },0) } } obj.show(); //this指向 show
-
箭头函数可以用
call
,apply
,bind
来改变this指向吗? -
不能!! 试图改变箭头函数的this是徒劳的。
var a = 10; var arr ={ a : 12 } var fn =() =>{ console.log(this.a) } var fn2= function(){ console.log(this.a) } fn() // 10 fn2() // 10 fn.call(arr) // 10 fn.apply(arr) // 10 var bound1 = fn.bind(arr); // 10 bound1(); // 10 fn2.call(arr) // 12 fn2.apply(arr) // 12 var bound2 = fn2.bind(arr); // 12 bound2(); // 12
-
-
作为对象的方法
-
当函数作为对象里的方法被调用时,它们的
this
是调用该函数的对象。var o = { prop: 37, f: function() { return this.prop; } }; console.log(o.f()); // 37
-
请注意,这样的行为,根本不受函数定义方式或位置的影响。在前面的例子中,我们在定义对象
o
的同时,将函数内联定义为成员f
。但是,我们也可以先定义函数,然后再将其附属到o.f
。这样做会导致相同的行为:var o = {prop: 37}; function independent() { return this.prop; } o.f = independent; console.log(o.f()); // 37
这表明函数是从
o
的f
成员调用的才是重点。 -
-
作为构造函数
-
当一个函数用作构造函数时(使用[new]关键字),它的
this
被绑定到正在构造的新对象。虽然构造器返回的默认值是
this
所指的那个对象,但它仍可以手动返回其他的对象(如果返回值不是一个对象,则返回this
对象)。function C(){ this.a = 37; } var o = new C(); console.log(o.a); // 37 function C2(){ this.a = 37; return {a:38}; } o = new C2(); console.log(o.a); // 38
-
-
原本的构造函数是window对象的方法,如果不用new操作符而直接调用,那么构造函数的执行对象就 是window,即this指向了window。现在用new操作符后,this就指向了新生成的对象
-
普通函数与构造函数的区别
function Person1(){ this.name = "小红"; var age = 22; window.height = 180; //普通函数this 指向window console.log(this) // window } function Person2(){ this.name = "小明"; var age = 21; window.height = 181; //构造函数里的 this指向新生成的person2 对象 console.log(this) //Person2 {name: "小明"} } var person = Person1(); var person2 =new Person2() // console.log 里的 this指向 window console.log(this.name) // 小红 console.log(this.age) // undefined console.log(this.height) // 181 // console.log(person.name) // 报错 // console.log(person.age) // 报错 console.log(person2.name) // 小明 console.log(person2.age) // undefined console.log(person2.height) // undefined
-
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。prototype将会作为一个指向原型对象的指针。
-
使用原型模式创建的实例对象,该对象通过this是可以相互访问的。
function Animal(name,age){ this.name=name; this.age=age; // 把 name ,age 放进实例对象之中 consloe.log(this) // Animal {name: "小苏", age: 20} } //在实例对象中添加方法 eat() Animal.prototype.eat=function(){ console.log(this.name +"吃"); this.play(); // this指向实例对象 }; //在实例对象中添加方法 play() Animal.prototype.play=function(){ console.log("玩"); this.sleep(); }; //在实例对象中添加方法 sleep() Animal.prototype.sleep=function(){ console.log("睡"); }; //该实例对象通过this相互访问 var dog=new Animal("小刘",20); //创建 Animal {name: "小苏", age: 20} 实例对象 dog.eat(); // 小刘吃 玩 睡