AboutFE icon indicating copy to clipboard operation
AboutFE copied to clipboard

18、This问题

Open CodingMeUp opened this issue 7 years ago • 3 comments

this是JS的关键字、代表函数运行时候生成的一个内部对象、只能在函数内部用。

函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象。

  • 情况一:纯粹的函数调用 函数的最通常用法,属于全局性调用,因此this就代表全局对象Global。
  function test(){ 
    this.x = 1; 
    alert(this.x); 
  } 
  test(); // 1 
  // 明this就是全局对象,对代码做一些改变: 
  var x = 1; 
  function test(){ 
    this.x = 0; 
  } 
  test(); 
  alert(x); //0 
  • 情况二:作为对象方法的调用 函数还可以作为某个对象的方法调用,这时this就指这个上级对象
  function test(){ 
    alert(this.x); 
  } 
  var o = {}; 
  o.x = 1; 
  o.m = test; 
  o.m(); // 1
  • 情况三 作为构造函数调用 所谓构造函数,就是通过这个函数生成一个新对象(object)。这时,this就指这个新对象。
 function test(){ 
    this.x = 1; 
  } 
  var o = new test(); 
  alert(o.x); // 1 
// 为了表明这时this不是全局对象,对代码做一些改变: 
  var x = 2; 
  function test(){ 
    this.x = 1; 
  } 
  var o = new test(); 
  alert(x); //2  表明全局变量x的值根本没变。 
  • apply调用 函数对象的一个方法,它的作用是改变函数的调用对象,它的第一个参数就表示改变后的调用这个函数的对象。因此,this指的就是这第一个参数
  var x = 0; 
  function test(){ 
    alert(this.x); 
  } 
  var o={}; 
  o.x = 1; 
  o.m = test; 
  o.m.apply(); //0  apply()的参数为空时,默认调用全局对象。因此,这时的运行结果为0,证明this指的是全局对象。  
      // 如果把最后一行代码修改为  o.m.apply(o); //1  运行结果就变成了1,证明了这时this代表的是对象o

CodingMeUp avatar Nov 27 '17 03:11 CodingMeUp

js中this的指向,如何改变,call和apply和bind的区别

在JavaScript中this可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式,this 绑定的对象即函数执行的上下文环境情况

1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window(非严格模式,在严格版中的默认的this不再是window,而是undefined)

2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。#### 3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象

// 作为对象方法调用
var test = {
    a : 5,
    b : 6,
    sum : function () {
        return this.a + this.b;     // 此处this = test
    }
}
alert(test.sum());     // 11// 作为函数调用

a = 4;
b = 3;
function sum(){
    return this.a + this.b;         // 此处this = window
}
alert(sum());      // 7

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
o.b.fn();
var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();

对于构造函数,this会指向new出来的实例
function Fn(){
    this.user = "萌爷";
}
var a = new Fn();
console.log(a.user); //萌爷如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
function fn()  
{  
    this.user = '萌爷';  
    return 1;
}
var a = new fn;  
console.log(a.user); //萌爷function fn()  
{  
    this.user = '萌爷';  
    return function(){};
}
var a = new fn;  
console.log(a.user); //undefined如何改变

new操作符会改变函数this的指向问题 首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。

apply或call,bind

  • cat.call(dog, a, b) = cat.apply(dog, [a, b]) = (cat.bind(dog, a, b))() = dog.cat(a, b) bind与apply、call最大的区别就是:bind不会立即调用,其他两个会立即调用,如果多次调用bind,那么多出来的次数都是无效的都是用来改变函数的this对象的指向的,第一个参数都是this要指向的对象,都可以利用后续参数传参。

将上述一个例子改造一下

var a = {
 user:"萌爷",
 fn:function(){
     console.log(this.user); //萌爷
 }
}
var b = a.fn;
var c = b.bind(a);
c();

CodingMeUp avatar Dec 12 '17 07:12 CodingMeUp

https://juejin.im/post/5c0c87b35188252e8966c78a

CodingMeUp avatar May 10 '20 09:05 CodingMeUp

总结

如果要判断一个运行中函数的 this 绑定, 就需要找到这个函数的直接调用位置。 找到之后 就可以顺序应用下面这四条规则来判断 this 的绑定对象。

  • new 调用:绑定到新创建的对象,注意:显示return函数或对象,返回值不是新创建的对象,而是显式返回的函数或对象。

使用new操作符调用函数,会自动执行以下步骤。

  1. 创建了一个全新的对象。
  2. 这个对象会被执行[[Prototype]](也就是__proto__)链接。
  3. 生成的新对象会绑定到函数调用的this。
  4. 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
  5. 如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用会自动返回这个新的对象。
  • call 或者 apply( 或者 bind) 调用:严格模式下,绑定到指定的第一个参数。非严格模式下,null和undefined,指向全局对象(浏览器中是window),其余值指向被new Object()包装的对象。

call就是改变函数中的this指向为thisArg,并且执行这个函数,这也就使JS灵活很多。严格模式下,thisArg是原始值是值类型,也就是原始值。不会被包装成对象 bind和call和apply类似,第一个参数也是修改this指向,只不过返回值是新函数,新函数也能当做构造函数(new)调用

  • 对象上的函数调用:绑定到那个对象。
  • 普通函数调用: 在严格模式下绑定到 undefined,否则绑定到全局对象。

ES6 中的箭头函数:不会使用上文的四条标准的绑定规则, 而是根据当前的词法作用域来决定this, 具体来说, 箭头函数会继承外层函数,调用的 this 绑定( 无论 this 绑定到什么),没有外层函数,则是绑定到全局对象(浏览器中是window)。 这其实和 ES6 之前代码中的 self = this 机制一样。 DOM事件函数:一般指向绑定事件的DOM元素,但有些情况绑定到全局对象(比如IE6~IE8的attachEvent)。

一定要注意,有些调用可能在无意中使用普通函数绑定规则。 如果想“ 更安全” 地忽略 this 绑 定, 你可以使用一个对象, 比如ø = Object.create(null), 以保护全局对象。

面试官考察this指向就可以考察new、call、apply、bind,箭头函数等用法。从而扩展到作用域、闭包、原型链、继承、严格模式等。这就是面试官乐此不疲的原因。

CodingMeUp avatar May 10 '20 09:05 CodingMeUp