this指向问题(未完待续)

245 阅读2分钟

this-函数内部的一个特殊对象,引用的是函数执行的环境对象
在函数调用前,this值并不确定。
也就是说,this是在函数执行时被绑定的,取决于函数的调用位置。

全局作用域中调用函数,this对象引用的是window

改变this指向

1.apply、call、bind

window.color = 'red';
var obj = {color: 'blue'};
function sayColor () {
    console.log(this.color);
}

sayColor(); //'red'
sayColor.call(obj); //'blue'
sayColor.apply(obj); //'blue'

2.构造函数中
this会指向实例对象

function People (name){
	this.name = name;
}
const child = new People('xiaopengyou');
console.log(child.name); //xiaopengyou

3.作为对象方法被调用
this指向该对象

window.color = '1';
var obj = {color: '2'};
function sayColor () {
    console.log(this.color);
}
obj.osay = sayColor;
obj.osay(); //'2'

3.闭包中的this
匿名函数的执行环境具有全局性,因此其this对象通常指向window。
有时编写闭包的方式不同,这一点可能并不明显。

  • 每个函数在被调用时都会自动取得两个特殊变量:this、argument。
  • 内部函数在搜索这两个变量时,只会搜索到其活动对象为止;
  • 因此永远不能访问外部函数中的这两个变量。
但是可以通过将外部作用域中的this对象保存在一个闭包能访问的变量里
var name = 'The Window';
var obj = {
    name:'obj',
    sayName: function(){
        var that = this; //保存外部作用域中的this对象‘obj’
        return function(){
            console.log(this.name);//'The Window'
            return that.name;//'obj'
        }
    }
}
console.log(obj.sayName()());

匿名函数的执行环境具有全局性

var name = 'window';
const user = {
    name: 'user',
    action: {
        name: 'action',
        getCount: function(){
            return this.name;
        } 
        //getCount:()=>this.name,
    }
};
const action = user.action;
const getCount = user.action.getCount;//这个赋值表达式的值是函数本身,
//所以this的值不能得到维持

console.log(user.action.getCount());//this:action  箭头:window
console.log(action.getCount());//this:action  箭头:window
console.log(getCount());//this:window  箭头:window

4.箭头函数中

  • this对象是定义时所在的对象,而不是使用时所在的对象
箭头函数可以让this指向固化,固化并不是因为箭头函数内部有绑定this的机制
实际原因是,箭头函数**根本没有自己的this,导致内部的this就是外部代码块的this**。
function Timer () {
    this.n = 10;
    this.m = 20;
    //箭头函数
    setTimeout(() => {
        this.n += 1; //this指向Timer
    },100);
    //普通函数
    setTimeout(function(){
        this.m += 1; //this指向window
    },100);
}
var timer = new Timer();
setTimeout(() => console.log('n',timer.n),200);//11
setTimeout(() => console.log('m',timer.m),200);//20
  • setTimeout执行时所在的作用域为window(this)**上述m不变
  • 箭头函数使其里面的this绑定定义时所在的位置 **n改变
var btn = document.getElementById('btn');
btn.addEventListener('click',function(){console.log(this)}); //button
btn.addEventListener('click',() => {console.log(this)}); //window
var handler = {
    message: 'handler',
    click: function (){
        console.log(this);
    }
}
//btn.addEventListener('click',handler.click); //button
btn.addEventListener('click',function(){
    console.log(this,'this')//button
    handler.click();        //指向handler对象
});

5.在class方法中调用

原型继承

function A(x){
    this.x = x;
}
A.prototype.x = 1;
function B(x){
    this.x = x;
}
B.prototype = new A();

var a = new A(2);
var b = new B(3);
delete b.x;
console.log(a.x,b.x); //2 undefined
var handler = {
    message: 'handler',
    click: function (){
        console.log(this);
    }
}
var btn = document.getElementById('btn');
//btn.addEventListener('click',handler.click); //button
btn.addEventListener('click',function(){
    console.log(this,'this')//button
    handler.click();        //指向handler对象
});
var bar = {
    myname: "bar", //注意。不是变量,字符串
    getName: function() {
        console.log(myname);
        console.log(this);
    }
}

function foo() {
    var myname = "foo";
    return bar.getName;
}
var myname = "global";
var _printName = foo();
_printName(); //"global" window
bar.getName(); //"global" bar对象