前言
看了3.0 this的前置了解,总算能知道如何判断this的指向了,那么下面的知识也不难理解了。
总结
- 作为普通函数,this指向window。
- 构造器调用,this指向返回的这个对象。
- 当函数作为对象的方法被调用时,this就会指向该对象。
- 箭头函数 箭头函数的this绑定看的是this所在函数定义在哪个对象下,就绑定哪个对象。如果有嵌套的情况,则this绑定到最近的一层对象上
箭头函数this的原理
this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
怎么改变this的指向呢?
1.使用es6的箭头函数;
2.在函数内部使用that = this;
3.使用apply,call,bind;
4.new实例化一个对象
bind,apply,call的区别
通过apply和call改变函数的this指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply是数组,而call则是arg1,arg2...这种形式。bind一个是返回一个函数,并不会立即执行第二个是带参数(第一个参数要指向的this,后面的的参数用来传递
正文
一、几种指向
1、直接作为普通函数去调用,this指向window
在全局作用域下函数直接被调用this绑定到全局对象,如调用window.fn1(this)
,this就是全局对象
console.log(this);
function fn1(){
console.log(this);
}
fn1();
2、函数嵌套含有this的内部函数,执行父函数时,this指向window
函数嵌套产生的内部函数的this不是其父函数,而是如fn0()
直接调用函数里的fn()
,也是直接调用this,this指向window。
function fn0(){
function fn(){
console.log(this);
}
fn()
}
fn0()
3、this在函数setTimeout、setInterval中执行,this指向window
当执行第一个this时,它指向当前document元素;当执行第二个this时,函数setTimeout、setInterval中的this指向window。
document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);
4、作为构造函数调用,this指向创建的这个对象
构造函数,并不直接调用this(直接调用this则是全局变量),先new一个函数创建一个实例,同时设置这个实例的proto属性指向prototype属性,执行当前函数,执行中当前的this
第一个this此时代表刚刚创建的这个对象(实例),然后赋值给变量p1、p2、p3,在构造函数原型上添加的printName,执行函数时输出的this也代表这刚刚创建并调用的这个对象(实例)
function Person(name){
this.name = name;
}
Person.prototype.printName = function(){
console.log(this.name);
};
var p1 = new Person('Byron');
var p2 = new Person('Casper');
var p3 = new Person('Vincent');
p1.printName();
p2.printName();
p3.printName();
5、当函数作为对象方法被调用,this指向该对象
首先obj1.fn被调用,fn前面有一个对象引用,所以首先输出的是对象 obj1,那么this 被自然绑定到该对象,第一个输出便是obj1,fn 中的“this”是指向全局对象,因此第二个被输出到控制台的是全局对象。
var obj1 = {
name: 'Byron',
fn : function(){
console.log(this);
}
};
obj1.fn();
//{name: "Byron", fn: ƒ}和全局对象
var fn2 = obj1.fn;
fn2()
假设var fn2 = obj1.fn;此时fn2被调用,所以下一个输出的结果也是全局变量
此时fn2和fn实质上是对同一个函数的引用,只是调用的绑定规则不一样。
6、DOM对象绑定事件,this指向事件源DOM对象
在事件处理程序中this代表事件源DOM对象(低版本IE有bug,指向了window),但是在 setTimeout函数中如果没有提前声明this的话,this则指向window。如this仍代表事件源DOM对象,那么就需要将this 赋值给一个新变量
document.addEventListener('click', function(e){
console.log(this);
var _document = this;
setTimeout(function(){
console.log(this);
console.log(_document);
}, 200);
}, false);
7、Function.prototype.bind
bind 作为任何函数的一个原型方法,都能找到。bind,返回一个新函数,并且使函数内部的this为传入的第一个参数
var name = 'global'
var App {
name ='app'
sayName = function(){
console.log(this.name)
}
}
App.sayName()
//app
当调用App.sayName()时,实际就是调用函数function,输出this.name,那么this代表的就是App里面的name,即app
假设继续执行:
var name = 'global'
var App {
name ='app'
sayName = function(){
console.log(this.name)
}
}
var obj1 ={
name:'nick'
}
App.sayName() //app
App.sayName.bind(window)() //global
App.sayName.bind(obj1)() // nick
App.sayName.bind(window)()
,函数.bind的作用返回一个新的函数,函数中若有this,那么则作为bind的第一个对象
App.sayName.bind(参数)
执行后返回一个函数(这里相当于生成了一个新的函数),而这里传递的参数,如window或者再声明一个变量,this就是这个传递的参数,那么继续执行之后,实质上就是执行 sayName里面的函数体,此时this === 参数
,则会输出对应的属性值
待续...