本文首发于个人 GitHub 博客前端
小白前端学习 JavaScript 过程当中遇到的第一道坎,大几率就是 this 了。曾经我也被 this 搞的很是头大,还看过很多博客,但我以为大多数文章写的有些复杂或者又引入了一些新的概念,加大了理解难度。本文就站在各位前辈大佬的肩膀上,作一下总结升华,目的就是让你们一次搞定 JavaScript 中的 this。git
fn
和 fn()
不同就行,fn()
是函数调用call
、apply
、bind
的函数调用就是隐式调用,反之就是显示调用fn = () => {}
这样的函数叫箭头函数就行call
的用法,知道 call()
的第一个参数能够指定 fn 的 this 就行,bind
和 apply
同理函数调用的时候肯定 this 指向,能够把 this 当作一个隐藏参数。github
var a = 10;
function fn() {
var a = 1;
console.log(this.a);
}
fn() // 调用的时候才肯定this,默认是undefined,浏览器把它改为了window,var声明的变量会自动挂到window下,因此输出10
复制代码
看这个函数的类型,若是是箭头函数,看它外面的 this。面试
var fn = () => {
console.log(this.id);
}
var id = 21;
foo(); // 21,由于外面的this是undefined,非严格模式下浏览器会自动转成window,var声明的变量被自动挂到window,因此输出21
复制代码
fn(1, 2)
转化成 fn.call(undefined, 1, 2)
浏览器
obj.fn('hello')
转化成 obj.fn.call(obj, 'hello')
markdown
arr[0]()
转化成 arr.0.call(arr, 'x')
app
来一道综合题一次性说完:函数
var id = 10
var obj = {
id: 1,
foo: function(){
console.log(this.id)
}
}
function fn (){ console.log(this) }
var arr = [fn, fn2]
var bar = obj.foo
obj.foo() // 1
bar() // 10
arr[0]() // arr
复制代码
function Person (name) {
this.name = name
}
var name = 'window'
var person1 = new Person('Varian')
console.log(person1.name) // Varian
复制代码
严格模式下值为 undefined 的 this 不会变成 windowoop
"use strict"; // 开启严格模式
var a = 10;
function foo () {
console.log('this1', this) // 'this1' undefined
console.log(window.a) // 10
console.log(this.a) // Uncaught TypeError: Cannot read property 'a' of undefined
}
console.log(window.foo) // f foo() {...}
console.log('this2', this) // 'this2' Window{...}
foo();
复制代码
let x = 10
const y = 20
function foo () {
console.log(this.x) // undefined
console.log(this.y) // undefined
}
foo();
console.log(window.x) // undefined
复制代码
看完有没有感受 this 其实也并不难呢?来几道综合题巩固一下吧!学习
结合 DOM
button.onClick = function(e) {
console.log(this);
}
复制代码
答案不是 button,而是不肯定,由于都没有调用,怎么知道 this 呢?
能够这么回答:由于没有调用,因此没法肯定 this,若是采用隐式调用的话,打印 button,若是使用显示调用,则打印自定义的 this。
超难面试题
let length = 10;
function fn() {
console.log(this.length);
}
let obj = {
length: 5,
method(fn){
fn()
arguments[0]()
}
}
obj.method(fn, 1);
复制代码
这道题有几大坑:let、window.length、arguments.length
因此答案也很是诡异
不肯定(window.length = 页面的iframe数量)
2(arguments.length = 实参长度,非形参)
复制代码
关于 window.length 的值,能够参见 MDN。
记住一“定”,二“转”,三特例就行,核心是两点:
obj.fn(1)
= obj.fn.call(obj, 1)
这样一来 this 就真相大白了!