在 JavaScript 中,this
是函数调用上下文。正是因为 this
的行为很复杂,因此在 JavaScript 面试中,老是会问到有关 this
的问题。javascript
作好的准备面试的方法是练习,因此本文针对 this
关键字整理了 7 个有趣的面试。前端
注意:下面的 JavaScript 代码段以非严格模式运行。java
如下代码输出什么:程序员
const object = { message: 'Hello, World!', getMessage() { const message = 'Hello, Earth!'; return this.message; } }; console.log(object.getMessage()); // => ?
输出: 'Hello, World!'
面试
object.getMessage()
是方法调用,这就是为何方法中的 this
等于 object
的缘由。segmentfault
方法中还有一个变量声明 const message ='Hello,Earth!'
,该变量不会影响 this.message
的值。数组
如下代码输出什么:浏览器
function Pet(name) { this.name = name; this.getName = () => this.name; } const cat = new Pet('Fluffy'); console.log(cat.getName()); // => ? const { getName } = cat; console.log(getName()); // =>?
输出:'Fluffy'
和 'Fluffy'
服务器
当一个函数被看成构造函数调用时( new Pet('Fluffy')
),构造函数内部的 this 等于构造的对象。微信
Pet
构造函数中的 this.name = name
表达式在构造的对象上建立 name
属性。
this.getName = () => this.name
this.getName =()=> this.name 在构造的对象上建立方法 getName
。由于使用了箭头函数,因此箭头函数中的 this 等于外部做用域中的 this
,也就是构造函数 Pet
。
调用 cat.getName()
和 getName()
会返回表达式 this.name
,其结果为 'Fluffy'
。
如下代码输出什么:
const object = { message: 'Hello, World!', logMessage() { console.log(this.message); // => ? } }; setTimeout(object.logMessage, 1000);
延迟1秒钟后,输出:undefined
尽管 setTimeout()
函数使用 object.logMessage
做为回调,但仍把 object.logMessage
做为常规函数而非方法调用。而且在常规函数调用中 this 等于全局对象,在浏览器环境中是 window
。这就是 logMessage
方法内的 console.log(this.message)
输出 window.message
的缘由,后者是 undefined
。
挑战:怎样修改这段代码使其输出 'Hello, World!'
?在下面的评论中写出你的解决方案*
补全代码,使结果输出 "Hello,World!"
。
const object = { message: 'Hello, World!' }; function logMessage() { console.log(this.message); // => "Hello, World!" } // Write your code here...
至少有 3 种方式能够把 logMessage()
做为对象上的方法调用。任何一个都被看做是正确答案:
const object = { message: 'Hello, World!' }; function logMessage() { console.log(this.message); // => 'Hello, World!' } // 使用 func.call() 方法 logMessage.call(object); // 使用 func.apply() 方法 logMessage.apply(object); // 使用函数绑定 const boundLogMessage = logMessage.bind(object); boundLogMessage();
如下代码输出什么:
const object = { who: 'World', greet() { return `Hello, ${this.who}!`; }, farewell: () => { return `Goodbye, ${this.who}!`; } }; console.log(object.greet()); // => ? console.log(object.farewell()); // => ?
输出: 'Hello, World!'
和 'Goodbye, undefined!'
当调用 object.greet()
时,在方法 greet()
内部 this
的值等于 object
,由于 greet
是常规函数。因此 object.greet()
返回 'Hello,World!'
。
可是 farewell()
是一个箭头函数,因此箭头函数中 this 的值老是等于外部做用域的 this
。farewell()
的外部做用域是全局做用域,其中 this
是全局对象。因此 object.farewell()
实际上会返回 'Goodbye, ${window.who}!'
,其结果为 'Goodbye, undefined!'
。
如下代码输出什么:
var length = 4; function callback() { console.log(this.length); // => ? } const object = { length: 5, method(callback) { callback(); } }; object.method(callback, 1, 2);
输出:4
使用 method()
内部的常规函数调用来调用 callback()
。由于在常规函数调用期间的 this 值等于全局对象,因此在 callback()
函数中 this.length
为 window.length
。
位于最外层的第一个语句 var length = 4
在全局对象上建立了属性 length
,因此 window.length
变为 4
。
最后,在 callback()
函数内部,`this.length
的值为 window.length
,最后输出 4
。
如下代码输出什么:
var length = 4; function callback() { console.log(this.length); // 输出什么 } const object = { length: 5, method() { arguments[0](); } }; object.method(callback, 1, 2);
输出:3
obj.method(callback, 1, 2)
用了 3 个参数进行调用:callback
、1
和 2
。结果 method()
内的arguments
特殊变量是有如下结构的相似数组的对象:
{ 0: callback, 1: 1, 2: 2, length: 3 }
由于 arguments[0]()
是对 arguments
对象上 callback
的方法调用,因此 callback
内部的 this
等于 arguments
。结果在 callback()
内部的 this.length
与 arguments.length
是相同的,都是3
。
若是你答对了 5 个以上,那么你对 this
关键字掌握的状况是很不错的。