JavaScript学习--this

什么是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高级程序设计》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值