this关键字在JavaScript中理解

对于js这语言来说,this关键字理解起来还真不是那么的容易,不像典型的面向对象语言,this就是指当前方法,js中,this是变动的,随着调用者的环境的变化而变化,主要是跟执行环境相关,与函数本身无关。
this.a // 此时this指向全局即window

var A = {
  name:'jack',
  showName:function(){
     return this.name;
  }
};
var B = {
  name:'lili'
}
A.showName() // jack 此时showName方法执行环境在A这,故showName方法中的this指向A
B.showName = A.showName;
B.showName() // 'lili' 此时this变指向了B;
var name = 'luce';
var show = A.showName;
show() // luce; 此时show的执行环境在全局即window,所以方法中的this指向了window

1、全局环境
在全局环境下,this就指向的全局window或是global

this === window // true
function A(){
  return this === window;
}
A() // true 执行环境为全局window

2、构造函数
构造函数中的this指向的是该构造函数的实例对象
之前说过在构造函数使用new操作符时会自动构建一个全新的对象,然后返回这个对象,其构造函数内部的this便指向了该对象

var o = function(p){
  this.p = p;
}
var obj = new o('hello');
obj.p // hello;
var f;
function F(){
  f = this;
}
var foo = new F();
f === foo //true;

3、对象上的方法
对象中的方法中出现的this指向是不固定的,当该方法赋值到另一个对象上的时候,这是this指向就变成了后面的那个对象

var name = 'lili'
var A = {
  name:'jack',
  show:function(){
    return this.name;
  }
}
var B = {
  name:'lucy'
}
A.show() // jack 此时this指向A
A.show.call(B) // lucy 通过call改变了this指向到B
(A.show = A.show)() // lili this指向了window
(false || A.show)() //lili this同样指向了window 实际上就相当于一个自执行函数,这种情况当然执行环境是在window下eg:(function(){return this.name})()

若对象中包含对象在包含方法中的this指向eg:

var a = {
  name:'jack',
  b:{
    name:'lucy',
    show:function(){
      return this.name;
    }
  }
}
a.b.show() // lucy 该执行环境是在a.b中,故而this指向了a.b
var t = a.b.show;
t.call(a) // jack //通过call方法将this指向为a

由于this指向的不确定性,在函数中尽量不要包含多层this

var o = {
  f1: function () {
    console.log(this);
    var f2 = function () {
      console.log(this);
    }();
  }
}
o.f1() // 将会依次输出o对象跟window对象这也是因为执行环境不一样导致

在执行f2自执行时,执行环境是在window下的,又由于变量的提升,导致实际运行代码

var temp = function () {
  console.log(this);
};

var o = {
  f1: function () {
    console.log(this);
    var f2 = temp();
  }
}

当然想要达到预想的结果可以有多中方式;比如可以通过call方法改变指向,或者通过临时变量来接受this等等
在使用this时,偶尔我们会遇到this的值为undefined的情况,这是因为在严格模式环境执行某个方法时,this便不再指向window,而是undefined eg:

var A = {
  name:'jack',
  show:function(){
    'use strict';
    return this.name;
  }
}
var a = A.show;
a() // TypeError: Cannot read property 'name' of undefined
此时this便不再是window,而是undefined
 在数组的遍历中使用this var o = {
  a:'hello',
  b:[1],
  f:function(){
    this.b.forEach(function(item){
      console.log(this.a+' '+item)
    })
  }
}
o.f() // undefined 1 这是因为在执行遍历的时候,this又指向了window
a = 'ck';
o.f() // ck 1 要想达到预期的结果,我们可以改改eg: var o = {
  a:'hello',
  b:[1],
  f:function(){
    var self = this;
    this.b.forEach(function(item){
      console.log(self.a+' '+item)
    })
  }
}
o.f() // hello 1 或者是在forEach遍历的时候指定上下文eg: var o = {
  a:'hello',
  b:[1],
  f:function(){
    this.b.forEach(function(item){
      console.log(this.a+' '+item)
    },this);
  }
}
o.f() // hello 1 或者是通过bind方法来动态改变this指向 var o = {
  a:'hello',
  b:[1],
  f:function(){
    this.b.forEach(function(item){
      console.log(this.a+' '+item)
    }.bind(this));
  }
}
o.f() // hello 1

call方法
在上文中有提到call方法

var o = {};
function f(){
  return this;
}
f() === window // true
f.call(o) === o // true 这样就能随意改变this指向了

call方法中带的参数应该是一个对象,如果参数为空、null和undefined,则默认传入全局对象,若不是对象,是原始值的话,则返回包装该值的包装对象

var o = {};
o.hasOwnProperty('toString') // false
o.hasOwnProperty = function(){return true;} // 手动改变了hasOwnProperty方法
o.hasOwnProperty('toString') // true
Object.prototype.hasOwnProperty.call(o,'toString') // false 通过call调用对象Object原生方法

apply 用法跟call类似,作用也是来改变this指向,唯一的区别是传递参数的方式不一样,apply参数是一个数组,而call参数是一个一个的参数
fun.call(this,[arg1,arg2...])
//找出数组中最小的值
Math.min.apply(null,[3,5,23,6]) // 3

bind 方法用来将函数体内的this绑定到某个对象,然后返回这函数eg:

var A = {
  name:'jack',
  show:function(){
    return this.name;
  }
}
A.show() // jack
var a = A.show;
a() // undefined
a = A.show.bind(A); // 通过bind方法将show方法内的this指向到A
a() // jack
bind方法的第一个参数便是需要指向的对象,后面的参数便是绑定原函数的参数

在使用eval的情况
1、间接调用 一般指向window
(0,eval)('this === window') //true
2、直接调用时,将会与执行环境有关

    function sloppyFunc() {
        console.log(eval('this') === window); // true
    }
    sloppyFunc(); //指向window
    function strictFunc() {
        'use strict';
        console.log(eval('this') === undefined); // true
    }
    strictFunc(); // 在严格模式下同样指向undefined
    // 构造函数下
    var savedThis;
    function Constr() {
        savedThis = eval('this');
    }
    var inst = new Constr();
    console.log(savedThis === inst); // true
    // 对象中的方法
    var obj = {
        method: function () {
            console.log(eval('this') === obj); // true
        }
    }
    obj.method();

代码可以在严格模式下执行会比想象中要好,在严格模式下会报错提示,容易知道问题出在哪里,就好比this来说,在严格模式下,this的指向有可能是undefined的情况,这时在调用this点操作符时就会报错,而非严格模式则不会报错,偶尔就会引起在运行时出现的未知问题,eg:

    function Point(x, y) {
        this.x = x;
        this.y = y;
    }
    var p = Point(7, 5); // 当忘记使用new操作符时
    console.log(p === undefined); // true
    // 下面得到的值是全局的,而不是P的实例属性:
    console.log(x); // 7
    console.log(y); // 5
PHP Warning: curl_exec() has been disabled for security reasons in /home/ftp/f/free49568/wwwroot/wp-content/themes/Variant/functions.php on line 490 百度已收录
分享