资讯专栏INFORMATION COLUMN

JavaScript 关于this的几道面试题及介绍

lifefriend_007 / 3095人阅读

摘要:对象方法中的当以对象里的方法的方式调用函数时,它们的是调用该函数的对象。注意,在何处或者如何定义调用函数完全不会影响到的行为。在这次执行期间,函数中的将指向。

原文链接

与其他语言相比,函数的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元素:

上面的alert会显示button。注意只有外层代码中的this是这样设置的:

在这种情况下,没有设置内部函数的this,所以它指向global/window对象(即非严格模式下调用的函数未设置this时指向的默认对象)。

(完)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/81964.html

相关文章

  • 前端周报:前端面试题及答案总结;JavaScript参数传递的深入理解

    摘要:前端面试题及答案总结掘金技术征文金三银四,金九银十,用来形容求职最好的几个月。因为的存在,至少在被标准化的那一刻起,就支持异步编程了。然而异步编程真正发展壮大,的流行功不可没。 showImg(https://segmentfault.com/img/bVVQOH?w=640&h=319); 1、2017前端面试题及答案总结 |掘金技术征文 金三银四,金九银十,用来形容求职最好的几个月...

    ermaoL 评论0 收藏0
  • 开开心心做几道JavaScript机试题 - 02

    摘要:前集回顾我们在开开心心做几道机试题中吐了槽,也顺势展开了机试题之旅,本章我们暂时压抑自己的吐槽之心,继续就题目前行。其实和都是构造函数,可以直接调用的。请尝试完成一个解析模块本题考查对的理解,各部分都是什么意思。 前集回顾 我们在开开心心做几道JavaScript机试题 - 01中吐了槽,也顺势展开了机试题之旅,本章我们暂时压抑自己的吐槽之心,继续就题目前行。仍然希望对各位正确认识Ja...

    seal_de 评论0 收藏0
  • 开开心心做几道JavaScript机试题 - 01

    摘要:碰到这种面试官,你只有是个题霸,再加上眼缘够才能顺利入围。只要按照我题目的思路,甚至打出来测试用例看看,就能实现这个题目了。答案根据的,对答案做出修正。另我的答案绝不敢称最佳,随时欢迎优化修正。但了解总归是好的。 我们在长期的面试过程中,经历了种种苦不堪言,不诉苦感觉不过瘾(我尽量控制),然后主要聊聊常见JavaScript面试题的解法,以及面试注意事项 忆苦 面试第一苦,面试官的土 ...

    liujs 评论0 收藏0
  • 几道前端面试题小记

    摘要:全局环境调用函数的对象实际为,所以函数内的指向构造函数通过构造函造函数生成了一个新对象,指向这个新对象。学习前端一个月,上一周面试了大概多家,收获的却是寥寥。为了效率,前端各方面的内容都有涉猎,深度却相当不足,面试时暴露各种问题。 最近面试了不少家,苦于前端经验薄弱,被各种血虐。做了不少家面试题,把各种不会的回来再做一遍,作为经验总结吧。 1.如何最优性能去重一个数组? 方法有好多,比...

    tulayang 评论0 收藏0
  • 几道前端面试题小记

    摘要:全局环境调用函数的对象实际为,所以函数内的指向构造函数通过构造函造函数生成了一个新对象,指向这个新对象。学习前端一个月,上一周面试了大概多家,收获的却是寥寥。为了效率,前端各方面的内容都有涉猎,深度却相当不足,面试时暴露各种问题。 最近面试了不少家,苦于前端经验薄弱,被各种血虐。做了不少家面试题,把各种不会的回来再做一遍,作为经验总结吧。 1.如何最优性能去重一个数组? 方法有好多,比...

    yhaolpz 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<