本文共 5228 字,大约阅读时间需要 17 分钟。
上周小组讲课讲的有this的指向,所以今天将上次讲课的知识点整理了一遍,再回忆一下。
this指向:在绝大多数情况下,函数的调用方式决定了this的值(运行时绑定),通俗的说,谁调用了我,我就指向谁。
1.首先了解window是浏览器对象
BOM的概述 browser object modal :浏览器对象模型。 浏览器对象:window对象。 Window 对象会在<body>
或 <frameset>
每次出现时被自动创建。
我们经常在js中调用一个函数通常是函数名加(),其实本质上是window.函数;例如:
var a=1;console.log(a);//输出为1console.log(window.a);//输出为1
2.现在开始说this,如刚开始所说,this的指向可以说是谁指向了我,我就指向谁,跟我们指向的地址去找this。
先来一个例子结合上一条对this进行一下了解function typeOne(a){ console.log('1 在html标签内声明函数,该方法this为:') console.log(this);}typeOne(1);//此时的输出结果为window,typeOne(1),可以写成window.typeOne(1)的形式。所以是window调用的函数,this就指向window。
2.1三种函数调用来讨论this指向
2.1.1:纯粹的函数调用function func() { console.log( this.a );}func();window.func();//undefined --this指向windowconsole.log(window.a);
这两个的输出都是undefined,window.func()中的this指向的是window,与func()一样。为什么结果是undefin呢?
这是因为this指向的是window,而window.a就相当于在全局定义了一个a的变量,但是没有进行赋值,所以输出的结果为undefined.
现在我们将a进行赋值
var a=5;function func() { console.log( this.a );}window.func();//undefined --this指向windowconsole.log(window.a);console.log(window);
此时的输出结果都为5,这是因为我们在全局定义了一个a变量,并且对a进行了赋值,所以此时window是由a这个属性的,他的属性值就是5,输出的window中有a这个属性,属性值为5
2.1.2:作为对象方法调用function func() { console.log( this.a );}var obj = { a: 42, func:func};obj.func();window.obj.func(); // 42 -- this指向obj
这种方式是obj调用的func(),此时obj中有属性a,且a的值为42,所以输出的结果为42
我们在上一段代码的基础上,加上这一段代码
var obj2={ a: 66, obj: obj}obj2.obj.func() //如果有多个对象调用我,那我就指向最后一个,即obj
此时可以理解为是obj2调用obj,obj调用func(),所以还是obj调用func(),所以结果为42
2.1.33.作为构造函数调用 构造函数就是通过这个函数可以生成一个新的对象,这是,this就指这个新对象。function test() { this.x = 1; console.log(this.x)}var obj = new test();obj// 1
这种方法obj对象中有x属性所以输出为1
var x=2;function test() { console.log(this.x)}var obj = new test();obj// undefined
这种方法得到结果为undefined,这是因为obj这个对象中有test函数,没有a独享,是obj调用的test()函数,所以为undefined
var x=2;function test() { this.x=1 console.log(this.x)}var obj = new test();obj// 1
这样子就更好理解了
2.2:通过三种方式对DOM节点添加点击事件 2.2.1.第一种方式:内敛方式 在html标签内声明函数 html代码为js代码为
function typeOne(){ console.log('1 在html标签内声明函数,该方法this为:') console.log(this);}
此时指的对像为window对象
这是因为点击按钮的时候,相当于执行了typeOne()函数,此时函数的执行范围是全局对象window,此时还是window调用了这个函数,所以this指向的还是window对象
2.2.2.第二种方式 :动态绑定,在js中为DOM对象绑定onclick事件two.onclick=function(){ console.log('2 onclick直接绑定,该方法this为:'); console.log(this);};
此时的输出结果为 button标签,此时this指向的是DOM对象,这是因为我们对DOM对象中的onclick属性赋值了一个函数,此时是DOm对象调用的这个函数,所以this指向的是DOM对象。这种绑定事件,只能绑定一次,如果多次绑定就会覆盖。
two.onclick=function(){ console.log('2 onclick直接绑定,该方法this为:'); console.log(this);};two.onclick=function(){ console.log('2 onclick直接绑定,第二次绑定,该方法this为:'); console.log(this);};
此时输出的结果为第二次绑定,this输出还是button。
下面在js中对DOM对象绑定事件的内部调用函数来判断该内部的this指向。
two.onclick=function(){ function f1(){ console.log('2.1 onclick直接绑定且函数内部来调用其他函数,该方法this为:'); console.log(this) }; f1(); function f2(){ console.log('2.2 onclick直接绑定且函数内部来调用其他函数,该方法this为:'); console.log(this) }; f2();};
两次的输出结果,对象都是指向的window,因为在内部依旧是window.f1(),window.f2()调用函数,所以输出的this是window。
2.2.3.第三种方式:使用监听事件进行绑定function typeThree(){ console.log('3 addEventListener第一次绑定,该方法this为:'); console.log(this);}three.addEventListener('click',typeThree)
此时输出的结果为button,this指向的是DOM对象,监听事件也是像DOm对象中的onclick属性赋值一个函数,此时是DOM对象调用这个函数和,this指向DOM对象。
下面对this谁指向我,我就指向谁的结合例子,依据地址来进行解析。代码如下function fn() { console.log(this.a );}var obj = { a: 2, fn: fn};var bar = obj.fn; //只是把fn赋值给bar,而决定 this 的值的是?var a = "我是全局的a";bar();
此是输出的结果为‘我是全局的a’,这是为什么呢。我们从根源上说起
首先,我们在js中声明了一个fn()函数,此时fn()函数有一个它自己的地址。我们对obj对象中的fn属性赋值了一个函数fn(),实际上是将fn()函数的地址赋值给了obj中fn属性。
而后,我们在全局定义了一个bar对象,我们将obj.fn赋值给了bar,因为obj.fn实际上是fn函数的地址,所以此时我们也将fn的地址赋值给了bar。
而,bar()是window对其进行调用,我们又在全局中定义了一个a属性,并将其进行了赋值,所以此时window对象中有a属性,此时的bar()函数与fn()函数的地址一样,调用bar函数可以说成是window调用了bar函数,也可以说成是window调用fn函数,此时window中有属性a,且他的属性值为“我是全局中的a”.
所以,最终的输出结果为我是全局中的a
2.3:定时器中的this指向var obj = { a: 42, func:function func () { console.log(this.a); }};setTimeout(obj.func, 1000);
输出的结果为undefined 这是因为setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致这些代码中包含的 this 关键字会指向 window (或全局)对象。
setTimeout(function(){ obj.func()}, 1000);//42setTimeout('obj.func()', 1000);//42
这两行代码执行的结果都是42
setTimeout('console.log("aaa")', 1000);//aaa
第二种传字符串那种,执行的是一行代码。
2.4.箭头函数中的this指向 箭头函数中的this指向 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this,即使是call,apply,bind等方法也不能改变箭头函数this的指向window.color='red'; var o={ color:'blue', sayColor:function(){ return ()=>{ console.log(this.color)}; } }; var sayColor = o.sayColor(); sayColor();//结果为blue
sayColor中没有color,它将去找上以层继承this,此时this指向o
window.color='red'; var sayColor=()=>{ console.log(this.color) } sayColor();
此时this指向window,函数sayColor的上一级是window,所以此时输出的结果为red
window.color='red';var o={ color:'blue', sayColor:()=>{ console.log(this.color) } }; o.sayColor();//red
此时函数o.sayColor的上一级是window,所以输出结果为red 上面那个箭头函数是写在函数里面,而这个箭头函数是函数体
window.color='red'; var o = { color: 'blue', b: () => console.log(this.color), c: function() { console.log( this.color) } } o.b(); // red o.c(); // blue
综合两种如上所示
转载地址:http://uhvqz.baihongyu.com/