JavaScript 关于this的几道面试题及引见

原文链接

与其他言语比拟,函数的this关键字在JavaScript中的行动略有差别。而且它在严厉形式和非严厉形式之间也有一些区分。

在绝大多数情况下,函数的挪用体式格局决议了this的值。this不能在实行时期被赋值,在每次函数被挪用时this的值也可能会差别。ES5引入了bind要领来设置函数的this值,而不必斟酌函数怎样被挪用的。

先来做几道面试题:

第一道:

var name = "caibaojian.com"; 
var person = {
  name: "kang",
  pro: {
    name: "Michael",
    getName: function() {
      return this.name;
    }
  }
};
console.log(person.pro.getName()); // Michael
var pepole = person.pro.getName;
console.log(pepole()); // caibaojian.com

第二道:

var name = "caibaojian.com";
var person = {
  name: "kang",
  pro: {
    name: "Michael",
    getName: function() {
      console.log(this);
      return this.name;
    }
  }
};
console.log(person.pro.getName()); // Object { name: "...", getName: () }, Michael
var pepole = person.pro.getName;
console.log(pepole()); // Window, caibaojian.com

第三道:

'use strict';
var name = "caibaojian.com"; 
var person = {
  name: "kang",
  pro: {
    name: "Michael",
    getName: function() {
      console.log(this);
      return this.name;
    }
  }
};
console.log(person.pro.getName()); // Object { name: "...", getName: () }, Michael
var pepole = person.pro.getName;
console.log(pepole()); // undefined

第四道:

var name = "caibaojian.com",
    person = {
      name : "kang",
      getName : function(){
       return function(){
         return this.name;
       };
      }
    };

console.log(person.getName()()); // caibaojian.com

下面一同看看关于this的用法:

一、全局高低文

在全局运转高低文中(在任何函数体外部),this指代全局对象,不管是不是在严厉形式下。在浏览器中,全局对象为window对象。

console.log(this.document === document); // true
console.log(this === window); // true
this.a = 37;
console.log(window.a); // 37

二、函数高低文

在函数内部,this的值取决于函数是怎样挪用的。

1、直接挪用

在非严厉形式下,this的值不会在函数实行时被设置,此时的this的值会默许设置为全局对象。

function foo(){
  return this;
}

foo() === window; // true

在严厉形式下,this将坚持他进入实行环境时的值,所以下面的this将会默以为undefined

function foo(){
  "use strict"; // 严厉形式
  return this;
}

foo() === undefined; // true

在严厉形式下,假如this未被实行的高低文环境定义,那末它将会默以为undefined

2、对象要领中的this

当以对象里的要领的体式格局挪用函数时,它们的this是挪用该函数的对象。

下面的例子中,当obj.f()被挪用时,函数内的this将绑定到obj对象。

var obj = {
  prop: 37,
  foo: function() {
    return this.prop;
  }
};

console.log(obj.foo()); // 37

注重,在那边或许怎样定义挪用函数完整不会影响到this的行动

在上一个例子中,我们在定义obj的时刻为其成员foo定义了一个匿名函数。然则,我们也能够起首定义函数然后再将其隶属到obj.foo。如许做this的取值也和上面一致:

var obj = { prop: 37 };

function independent() {
  return this.prop;
}

obj.foo = independent;

console.log(obj.foo()); // 37

这说明this的值只与函数foo作为obj的成员被挪用有关联。

相似的,this的绑定只受最靠近的成员援用的影响。

鄙人面的这个例子中,我们把一个要领g看成对象obj.b的函数挪用。在这次实行时期,函数中的this将指向obj.b。事实上,这与对象自身的成员没有多大关联,最靠近的援用才是最主要的。

var obj = { prop: 37 };

function independent() {
  return this.prop;
}

obj.b = {
  g: independent,
  prop: 42
};

console.log(obj.b.g()); // 42

3、原型链中的this

雷同的观点在定义在原型链中的要领也是一致的。假如该要领存在于一个对象的原型链上,那末this指向的是挪用这个要领的对象,表现得好像是这个要领就存在于这个对象上一样。

var obj = {
  f : function(){ 
    return this.a + this.b; 
  }
};
var p = Object.create(obj);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

在这个例子中,对象p没有属于它自己的f属性,它的f属性继续自它的原型。然则这关于终究在obj中找到f属性的查找历程来讲没有关联;查找历程起首从p.f的援用最先,所以函数中的this指向p。也就是说,由于f是作为p的要领挪用的,所以它的this指向了p。这是JavaScript的原型继续中的一个风趣的特征。

4、gettersetter中的this

雷同的观点也适用时的函数作为一个getter或许setter挪用。作为gettersetter函数都邑绑定this到从设置属性或获得属性的谁人对象。

function modulus(){
  return Math.sqrt(this.re * this.re + this.im * this.im);
}

var obj = {
  re: 1,
  im: -1,
  get phase(){
    return Math.atan2(this.im, this.re);
  }
};

Object.defineProperty(obj, 'modulus', {
  get: modulus,
  enumerable: true,
  configurable: true
});

console.log(obj.phase, obj.modulus); // -0.785 1.414

5、组织函数中的this

当一个函数被作为一个组织函数来运用(运用new关键字),它的this与即将被建立的新对象绑定。

注重:当组织器返回的默许值是一个this援用的对象时,能够手动设置返回其他的对象,假如返回值不是一个对象,返回this

function Fn(){
  this.a = 37;
}

var obj = new Fn();
console.log(obj.a); // 37

function Foo(){
  this.a = 37;
  return { a: 38 };
}

obj = new Foo();
console.log(obj.a); // 38

6、callapply

当一个函数的函数体中运用了this关键字时,经由过程一切函数都从Function对象的原型中继续的call()要领和apply()要领挪用时,它的值能够绑定到一个指定的对象上。

function add(c, d){
  return console.log(this.a + this.b + c + d);
}

var obj = {
  a: 1,
  b: 3
};

add.call(obj, 5, 7); // 1 + 3 + 5 + 7 = 16
add.apply(obj, [10, 20]); // 1 + 3 + 10 + 20 = 34

运用callapply函数的时刻要注重,假如通报的this值不是一个对象,JavaScript将会尝试运用内部 ToObject操纵将其转换为对象。因而,假如通报的值是一个原始值比方7foo,那末就会运用相干组织函数将它转换为对象,所以原始值7经由过程new Number(7)被转换为对象,而字符串foo运用new String('foo')转化为对象,比方:

function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7); // [object Number]

7、bind()要领

ECMAScript 5引入了Function.prototype.bind。挪用fn.bind(someObject)会建立一个与fn具有雷同函数体和作用域的函数,然则在这个新函数中,this将永远地被绑定到了bind的第一个参数,不管这个函数是怎样被挪用的。

function fn(){
  return this.a;
}

var g = fn.bind({ a: "azerty" });
console.log(g()); // "azerty"

var obj = {
  a: 37,
  foo: fn,
  go: g
};
console.log(obj.foo(), obj.go()); // 37, "azerty"

8、DOM事宜处置惩罚函数中的this

当函数被用作事宜处置惩罚函数时,它的this指向触发事宜的元素(一些浏览器在动态增加监听器时不恪守这个商定,除非运用addEventListener)。

// 猎取文档中的一切元素的列表
var elements = document.getElementsByTagName('*');

for(var i = 0; i < elements.length; i++){
  // 当元素被点击时,就会变成蓝色
  elements[i].addEventListener('click', function (e) {
    e.stopPropagation();
    console.log(this);
    console.log(e.currentTarget);
    console.log(e.target);
    // 上面3个值是一样的
    this.style.backgroundColor = '#A5D9F3';
  });
}

9、内联事宜处置惩罚函数中的this

当代码被内联处置惩罚函数挪用时,它的this指向监听器地点的DOM元素:

<button onclick="alert(this.tagName.toLowerCase());">
  Show this
</button>

上面的alert会显现button。注重只要外层代码中的this是如许设置的:

<button onclick="alert((function(){return this})());">
  Show inner this
</button>

在这类情况下,没有设置内部函数的this,所以它指向global/window对象(即非严厉形式下挪用的函数未设置this时指向的默许对象)。

(完)

    原文作者:小小赵老汉
    原文地址: https://segmentfault.com/a/1190000008590012
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞