什么是this
- this对象是在运行时基于函数的执行环境绑定的,即在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。
打开浏览器的控制台,打印this会输出window对象。
这里顺便介绍一下window对象。
window对象
很多对象和浏览器窗口进行交互。这些对象有window、document、location、navigator和screen等,他们统称为BOM(Brower Object Model)。
- Window 对象表示浏览器中打开的窗口。
- 如果文档包含框架(frame 或 iframe 标签),浏览器会为 HTML 文档创建一个 window 对象,并为每个框架创建一个额外的 window 对象。
上文打印出来的Windows对象有很多属性和方法。window以下四个方法最常用。
1、moveBy(x,y):该方法表示把浏览器窗口相对于当前位置水平移动x个像素,垂直移动y个像素。x、y为负数时则向相反的方向移动。
2、moveTo(x,y):该方法表示把窗口移动到用户屏幕(x,y)处,使用负数表示会把窗口移除屏幕。
3、resizeby(x,y):表示相当于浏览器窗口的当前大小,把宽度增加了x个像素,高度增加y个像素,(x,y)为负数表示窗口缩小程度。
4、resizeTo(x,y):表示把窗口宽度调整到x像素,把窗口高度调整到y像素,(x,y)不能为负数。
这四个方法,屏幕的坐标原点都是在左上角,x轴的正方向是从左到右,y轴的正方向为从上到下。
open()和close()
windows对象另外一个常用的方法就是open(),它主要用来打开新的窗口。它有四个参数分别是新窗口url、新窗口名称、特征字符串说明、新窗口是否替换当前载入页面的布尔值,一般是使用前两个或者前三个参数。例如window.open(“url”,“_blank”);这段代码可以解释为用户单击一个链接,这个链接在新窗口打开。也可以设置其他的参数比如说left、top、height、width等。比如说window.open(“url”,“_blank”,“height=200width=300,top=30,left=40,resizeble=yes”);。另外还可以调用close()方法关闭新建的窗口:window.close();如果有新建窗口有代码段,可以用window.close();关闭其自身。
也可以直接调用open()、close(),因为这些函数此时在全局作用域下。
open('http://www.baidu.com','_blank',"height=200");
更多解释可以查看window对象和w3school关于window对象的解释
上下文环境
调用this时所在的对象就是其上下文环境
ES5中this对象
var name = "this window";
var object = {
name: "my object",
getNameFunc: function() {
return function() {
return this.name;
}
}
}
alert(object.getNameFunc()()); // "this window"
这是由于object.getNameFunc()()实际上调用了一个匿名函数,可以看到调用object.getNameFunc()函数之后返回了原本定义在getNameFunc()函数中的匿名函数。
console.log(object.getNameFunc());
// 输出结果ƒ () { return this.name; }
而object.getNameFunc()()实际上就是调用匿名函数ƒ ();此时由于ƒ ()的作用域是在全局下。(匿名函数的执行环境具有全局性,因此其this函数通常指向window。来自《JavaScript高级程序设计》)此时函数返回的就是全局作用域下的name。
函数在调用时都会自动取得两个特殊变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。
var myobject = {
foo: "bar",
func: function() {
var self = this;
console.log(this.foo); // bar
console.log(self.foo); // bar
(function(){
console.log(this.foo); // undefined
console.log(self.foo); // bar
})();
}
};
myobject.func();
此时self指向的是myobject,在匿名函数中this指向全局,而self保存了外部作用域的this对象,因此可以在匿名函数中访问到foo。(外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问该对象了)。关于闭包和作用域,会再写几篇来加深理解。
ES6中箭头函数
什么是箭头函数
ES6 允许使用“箭头”(=>)定义函数。
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
箭头函数使得函数定义简洁,使用方便。具体的使用方法戳阮一峰老师的ES6教程。
箭头函数有几个使用注意点。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
箭头函数的this
var fun = () => {console.log(this};
fun(); // 打印出window对象
这是由于箭头函数使得this绑定了定义时所在的作用域,即window。
箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域。
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭头函数
setInterval(() => this.s1++, 1000);
// 普通函数
setInterval(function () {
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0
上面代码中,Timer函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)。所以,3100 毫秒之后,timer.s1被更新了 3 次,而timer.s2一次都没更新。
this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
下面的代码之中有几个this?
function foo() {
return () => {
return () => {
return () => {
console.log('id:', this.id);
};
};
};
}
var f = foo.call({id: 1});
var t1 = f.call({id: 2})()(); // id: 1
var t2 = f().call({id: 3})(); // id: 1
var t3 = f()().call({id: 4}); // id: 1
上面代码之中,只有一个this,就是函数foo的this,所以t1、t2、t3都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this。
ES5的this和箭头函数的this的不同和应用情景
前面提到this绑定的是运行时所处的对象,而箭头函数使得this绑定了的是定义时所处的对象,即使得this从“动态”变成“静态”。
比如点击按钮事件是需要绑定的,此时不适合用箭头函数来指向对象。
var button = document.getElementById('press');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
定义函数的方法,且该方法内部包括this,也不适合用箭头函数。
const cat = {
lives: 9,
jumps: () => {
this.lives--;
}
}
cat.jumps()方法是一个箭头函数,如果是普通函数,该方法内部的this指向cat;而箭头函数,使得this指向全局对象,因此不会得到预期结果。
ps:个人感觉关于this的坑还要等总结完闭包、作用域、call、apply等知识点才能真正理解。后面慢慢填坑(手动捂脸)。
参考:
阮一峰老师的ES6教程
https://baijiahao.baidu.com/s?id=1607859600311368314&wfr=spider&for=pc
《JavaScript高级程序设计》