关于this,MDN是这样描述的
ES2015 引入了箭头函数,箭头函数不提供自身的 this 绑定(
this
的值将保持为闭合词法上下文的值)。
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)
this
都指向全局对象。
在函数内部,
this
的值取决于函数被调用的方式。
可能直接看mdn文档有点抽象,下面看一下,另一种说法,看完之后,再去看mdn文档,突然就豁然开朗了, 我是这样的感觉的。
开始前先看一下Javascript中的函数调用
JS里面有三种函数调用形式
func(p1,p2)
obj.child.method(p1,p2)
func.call(context,p1,p2)
一般初学者都是用前两种,但是第三种才是正常的调用形式: 其他两种都是语法糖,可以等价地变为call形式
func(p1,p2)等价于
func.call(undefined,p1,p2)
obj.child.method(p1,p2)等价于
obj.child.method.call(obj.child,p1,p2)
记住了,this就是函数调用中的转成call的第一个参数
func.call(undefined,p1,p2) // this是undefined,浏览器会把undefined转换成window
obj.child.method.call(obj.child,p1,p2) // this是obj.child
日常开发中,涉及到的this的两种使用方法,其实就是上面说的:
隐式传递:
fn(1,2) // 等价于fn.call(undefined,1,2)
obj.child.fn(1) //等价于 obj.child.fn.call(obj.child,1)
显示传递
fn.call(undefined,1,2)
fn.apply(undefined,[1,2])
看一下几个常见的关于this的考题
例题一:
下面的函数调用中this分别是什么?
var a = {
name:'里面的name',
sayName:function(){
console.log("this.name = " + this.name)
}
}
var name = "外面的name"
function sayName(){
var sss = a.sayName
sss(); //this.name=?
a.sayName(); //this.name=?
(a.sayName)(); //this.name=?
(b = a.sayName)(); //this.name=?
}
sayName();
方法:把所有的函数调用改为call的写法
-
sayName() 就等价于sayName.call(undefined),这个调用的this就是window
-
sss() 等价于sss.call(),this就是window,即外面的name
-
a.sayName() 等价于a.sayName.call(a),this就是a,即里面的name
-
(a.sayName)() 等价于 a.sayName(),【解释:因为在js里面,加不加括号都一样】,即等价于a.sayName.call(a), this就是a,就是里面的name
-
(b = a.sayName)() 等价于第一种情况【解释:sss = a.sayName,sss()】这种,于是等价于b(),等价于b.call(),这里的this指向window,即外面的name,现在控制台看一下输出结果:
而下面这段代码是把上面那段代码用call改写后的样子,可以对比看看,以后尽量写调用都用call,这样显得逼格高一点:
var a = {
name:'里面的name',
sayName:function(){
console.log("this.name = " + this.name)
}
}
var name = "外面的name"
function sayName(){
var sss = a.sayName
sss.call(undefined); //this是undefined
a.sayName.call(a); //this是a
(a.sayName).call(a); //this是a
(b = a.sayName).call(undefined); //this是undefined
}
sayName();
例题二:
代码如下:
var length = 10
function fn(){
console.log(this.length)
}
var obj = {
length:5
method:function(fn){
fn();
arguments[0]();
}
}
解题方法:把所有的函数调用改成call的写法
obj.method(fn,1) 等价于 obj.method.call(obj,fn,1),等价于obj.method.call(obj,arguments) //其中arguments=[fn,1]
fn() 等价于 fn.call(undefined) // this是指的是length=10 arguments[0] 等价于 arguments.0.call(arguments)// this指的是arguments,即this就是[fn,1],this.length = 2,[fn,1].length = 2
控制台输出结果如下所示:
总结:
this就是一个函数调用,call改写后的第一个参数
比如func() 改成后func.call(undefined)//undefined是占位符,占第一个位置,浏览器会自动转成window 这里是this就是window
另外,箭头函数没有this
因为this对于js而言确实不是太好的东西,箭头函数应运而生
console.log(this) //打印出window
let fn = () => console.log(this)
fn() //调用fn,打印出window
上面这段代码表示,箭头函数里面的this就是外面的this,就是外面是什么里面是什么 加上call也没有用 fn.call({name:'liulei'}) //打印出window,而不是 {name:'liulei'}
而如果fn是普通函数,则this会改变
总结
看了上面的所说的,再去看MDN文档里面关于this的描述,感觉清晰明朗了许多。
本文资料参考