龙空技术网

JavaScript中this的理解

陆荣涛 271

前言:

目前朋友们对“jsthiswindow”大体比较关怀,你们都想要知道一些“jsthiswindow”的相关知识。那么小编也在网上汇集了一些对于“jsthiswindow””的相关文章,希望同学们能喜欢,看官们一起来学习一下吧!

在 JavaScript 编程中,this 关键字非常重要,也比较难理解,经常让初学者比较迷惑,所有今天我们一起来聊一下this关键字。

一.this的概述

this是Javascript语言的一个关键字,它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,随着函数使用场合的不同,this的值会发生变化,但是有一个总的原则,那就是this指的是调用函数的那个对象。

总结:谁调用了这个函数,this指向谁(对象)

二.this的指向

因为this存在于函数内部,通过不同的函数来检测this基本指向。

1.如果函数前面没有对象去调用,那么指向window,但是ES5新增的严格模式除外,因为在严格模式下this指向undefined。

代码如下:普通函数:function fn() { console.log(this); }fn();//windowwindow.fn();//window解析:普通函数直接调用,默认里面的this都是指向window,同时我们说函数也是window下面的方法,所以也可以通过window来调用,但结果同样指向window."use strict";//添加严格模式function fn() { console.log(this); //window}fn();//undefinedwindow.fn();//window解析:严格模式下面如果直接调用函数,根据严格模式的语法行为改变里面的this是指向undefined,但window去调用依然还是指向window自执行函数:!(function () { console.log(this); //window})();解析:下面的情况和上面一致,因为是子调用,即前面没有对象调用都指向window,严格模式下面指向undefined函数表达式:var声明的函数表达式,同上面的情况一致。var fn1 = function(){  console.log(this); }fn1();//windowwindow.fn1();//windowlet声明的函数表达式let fn1 = function(){  console.log(this); }fn1();//windowwindow.fn1();//这里会报错 window.fn1 is not a function,因为let声明的函数表达式不是window下面方法,(let具有块作用域和暂时性死区)

2.事件处理函数,自定义对象里面的方法的this指向,根据谁调用函数this指向谁的特性,这里的this都指向当前操作的对象。

document.onclick = function(){ console.log(this);//document}解析:因为是document通过事件类型click触发了此函数,所以函数内部的this指向document,事件绑定addEventListener也一样。const obj = { name:'zhangsan', age:18, showName:function(){  console.log(this);// obj  console.log(this.name);//zhangsan }}obj.showName();解析:原理同上谁调用了函数,函数内部的this指向谁,这里的showName是obj对象下面的方法,通过obj对象调用,所以指向obj对象。

3.构造函数里面的this指向

因为构造函数的外表跟普通函数差不多,主要区别在于被调用的方式。当用 new 运算符调用函数时,该函数总会返回一个对象,通常情况下,构造函数里的this就指向返回的这个对象。

let MyClass = function(){   this.name = 'zhangsan'; }; let obj = new MyClass(); console.log(obj.name); //zhangsan 解析:构造函数里的this就指向返回的这个对象但用new调用构造函数时,还要注意一个问题,如果构造函数显式地返回了一个 object 类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前的this。let MyClass = function(){      this.name = 'zhangsan';      return { //显式地返回一个对象        name: 'lisi'      } }; let obj = new MyClass(); console.log (obj.name); //lisi 如果构造函数不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成上述问题,主要是new关键字调用函数,函数内部隐式返回this造成的。let MyClass = function(){      this.name = 'zhangsan'      return 'lisi';}; let obj = new MyClass(); console.log(obj.name); // 输出:zhangsan

4.箭头函数的this指向。

ES6新增了箭头函数,对于普通函数来说,内部的this指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的this对象,内部的this就是定义时上层作用域中(父级作用域)的this。也就是说,箭头函数内部的this指向是固定的,相比之下,普通函数的this指向是可变的。

const obj = { a:1};const fn = function () { alert(this.a);//输出1,因为调用时修改了this指向,所以this指向obj};fn.call(obj); //本来this指向window,通过call(下文有讲解)改变this指向obj,最终的this就变成objconst fn = () => { alert(this.a);//输出undefined,因为window下面没有a属性。};fn.call(obj);//代码里面使用了箭头函数,this就不会受到影响,依然指向windowdocument.onclick = () => { alert(this); //window,this来自于父级,如果没有父级,指向window};document.onclick = function () {    alert(this); //document,因为document调用了此函数    window.setInterval(() =>{      alert(this); //document,因为使用了箭头函数,this指向外层的函数里面的this.    }, 1000);};

三.修改this指向的方式。

1.利用call,apply,bind方法。

函数下面有三个方法,call,apply,bind都可以改变this的指向,下面我们来具体演示这三个方法的应用和区别。

call方法:call方法的第一个参数就是新的this指向, 从第二个参数开始表示函数自身的参数。const obj = {    a: 100,};function sum(x, y) { console.log(this.a + x + y);}sum(3,7);//underfined + 3 + 7 = NaN解析:直接调用,this指向window,window下面没有a属性,所以window.a是undefinedsum.call(obj, 3, 7); //100 + 3 + 7 = 110解析:通过call改变this,让其指向obj,obj下面具有a属性,所以obj.a是100
apply方法:apply方法的第一个参数就是新的this指向, 第二个参数是一个数组或者类数组,里面的值依然是函数自身的参数。const obj = {    a: 100,};function sum(x, y) { console.log(this.a + x + y);}sum(3,7);//underfined + 3 + 7 = NaN解析:直接调用,this指向window,window下面没有a属性,所以window.a是undefinedsum.apply(obj, [3, 7]); //100 + 3 + 7 = 110 注意中括号是apply的第二个参数必须是数组或者类数组。解析:通过apply改变this,让其指向obj,obj下面具有a属性,所以obj.a是100call和apply的简单应用var obj1 = {  name: 'zhangsan' }; var obj2 = {  name: 'lisi' }; window.name = 'window'; var getName = function(){  alert ( this.name ); }; getName(); // 输出: window getName.call( obj1 ); // 输出: zhangsan getName.call( obj2 ); // 输出: lisi
bind方法:bind方法的第一个参数就是新的this指向, 从第二个参数开始表示函数自身的参数,但bind 是返回对应函数体,便于稍后调用,apply、call则是立即调用const obj = {    a: 100,};function sum(x, y) { console.log(this.a + x + y);}sum(3,7);//underfined + 3 + 7 = NaN解析:直接调用,this指向window,window下面没有a属性,所以window.a是undefinedsum.bind(obj, 3, 7)(); //100 + 3 + 7 = 110  注意这里需要再次调用解析:通过bind改变this,让其指向obj,obj下面具有a属性,所以obj.a是100bind的使用场景案例:将fn函数内部的this指向obj对象,2s后输出this.num的值。window.num = 100; //window添加属性const obj = {  num: 1000}function fn() { console.log(this.num);}fn(); //100 这里的this指向windowwindow.setInterval(fn.call(obj), 2000); //此时的定时器无效,已经调用fn函数,window.setInterval(fn.apply(obj), 2000); //此时的定时器无效,已经调用fn函数window.setInterval(fn.bind(obj), 2000); //定时器的第一个参数是函数体或者函数名称,bind返回的就是函数体,所以吻合需求。

2.将正确的this存储。

通过变量将需要的this存储下来,然后在函数内部利用存储的this达到我们的目标。

window.num = 2;function fn() { console.log(this.num);}const obj = {    num: 1,    shownum: function() {        let _this = this;// 通过变量将需要的this存储下来        return function() {         console.log(_this.num); //调用存储的this        }    }}obj.shownum(); 

3.借用其他对象的方法

借用其他对象方法的第一种场景是借用构造函数,通过这种技术,可以实现一些类似继承的效果:

let A = function( name ){  this.name = name; }; let B = function(){  A.apply( this, arguments ); }; B.prototype.getName = function(){  return this.name; }; var b = new B( 'zhangsan' ); console.log( b.getName() ); // 输出: 'zhangsan' 

借用其他对象方法的第二种场景是借用arguments

我们知道函数的参数列表arguments是一个类数组对象,虽然它也有“下标”,但它并非真正的数组,所以也不能像数组一样,进行排序操作或者往集合里添加一个新的元素。这种情况下,我们常常会借用Array.prototype对象上的方法。比如想往arguments中添加一个新的元素,通常会借用Array.prototype.push:(function(){  Array.prototype.push.call( arguments, 3 );  console.log ( arguments ); // 输出[1,2,3] })( 1, 2 ); 在操作 arguments 的时候,我们经常非常频繁地找 Array.prototype 对象借用方法。

四.和this相关的一些经典案例解读

var name = "The Window";var object = {    name : "My Object",    getNameFunc : function(){        return function(){         return this.name;        };    }};alert(object.getNameFunc()());//"The Window"解析:var声明的变量是window下面的属性object对象里面存在方法getNameFunc,而且这个方法的返回值也是一个函数,必须再次调用。通过返回的函数里面存在this,但是这里的this不是通过object进行调用,因为object.getNameFunc()返回的是一个函数体(普通的函数表达式),需要对函数体进行再次调用,而再次调用就和object对象没有关系了,所以这里的this不会指向object,而是指向window,结果输出"The Window"var name = "The Window";var object = {    name : "My Object",    getNameFunc : function(){        var _this = this;        return function(){         return _this.name;        };    }};alert(object.getNameFunc()()); //"My Object"解析:这里大部分情况和上面的一致,区别是object.getNameFunc方法里面提前将指向object对象的this存储为变量,并且在返回函数体的时候使用了这个变量,所以返回的函数中的this就是object.getNameFunc方法里面的this,即指向了object对象,结果输出 "My Object"

标签: #jsthiswindow