代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="div0"></div>
</body>
<script>
window.id = 'window';
document.getElementById('div0').onclick = function(){
alert(this.id);
var callback = function(){
alert(this.id)
}
callback();
};
</script>
</html>
第一个输出"div0"可以理解很正常,为何第二个输出的是"window",callback是内部的函数他应该和外部的this都隐式调用指向div0,为何外部指向div0,内部指向window?
于是尝试命令行运行:
window.name = "window"
var text = function(){
name = "text";
alert(this.name);
var callback = function(){
alert(this.name)
}
callback()
}
text()
结果输出两次"text"
两者矛盾了吧,已晕望大神指点
this 指向的是方法属性的所有者,第一个方法的所有者是DOM元素, 内部函数call由于没有申明所有者所以他的所有这是window
你描述的两种情况都可以佐证第一个this
指向DOM
,第二个this
指向window
。this
关键是看执行环境, 第一次在DOM
中,这个不需要太多解释; 第二次相当于window.callback()
, 所以this
指向window
。
你描述的第二种场景出现你理解的差异是因为name = "text";
, 这一步赋值操作, 使得window.name = "text"
, 所以执行callback()
会打出text
。
我觉得 callback 又不是外部那个function的属性,所以callback里的this不会指向到外面那个function那边去。
至于为什么第二个例子都是text呢???
亲,里面的name忘了var了,没var会被当成全局,不信你再试试window.name看还是不是"window"
关于你验证想法的例子楼上都说出错误了。
补充:
1.如果事件函数中有一个内部函数func,在事件内部调用func时,func函数内部this实际指向window。
2.this的隐式绑定是作为对象
的方法调用时才能生效。
3.对于1.我们可以使用call方法来修正
window.id = 'window';
document.getElementById('div0').onclick = function(){
alert(this.id);
var callback = function(){
alert(this.id)
}
callback.call(this);
};
window.name = "window";
var text = function() {
// name 没有用 var(或者 let、const)限定,是全局变量,即 window.name
name = "text";
// 参考下面 ①
alert(this.name);
var callback = function() {
// 这个 this 参考 ②
alert(this.name);
};
// ② 非对象方法方式调用,里面的 this 是全局对象,即 window
callback();
};
// ① 非对象方法方式调用,text() 内部的 this 是全局对象,即 window
text();
所以自始至终你都是在操作同一个 name
,即 window.name
。如果想要理解 this
,可以改一下代码
window.name= "window";
var obj = {
text: function() {
// 这两个 this 指的 obj,参考 ①
this.name = "text";
alert(this.name);
// callback 内部的 this 参考 ②
// 为了使用这里的 this,即 obj,可以用一个局部变量缓存
var _this = this;
var callback = function() {
// 输出 widnow.name
alert(this.name);
// 输出 obj.name
alert(_this.name);
};
// ② 对方法调用,callback() 内部的 this 是全局对象,即 window
callback();
}
};
// ① 方法调用,text 内部的 this 是 obj
obj.text();
// 这里的 obj.name 已经在 obj.text() 中赋值为 "text" 了
alert(obj.name);
上面都是用的 es5 语法,如果用 es6 的箭头函数,或者说 Lambda 语法,就不需要缓存 _this
。
现在不是所有浏览器都支持 es6 语法,所以实际使用的过程中一般需要通过 babel 之类的工具编译成 es5。这里提出来只是顺着这个问题的知识点,多一个参考答案。
var obj = {
text() {
this.name = "text";
var callback = () => {
// Lambda 不改变作用域,这里的 this 就是 obj
// this.name 就是 "text"
alert(this.name);
};
}
};
obj.text();