1、this
在函数执行时,this 总是指向调用该函数的对象。要判断 this 的指向,其实就是判断 this 所在的函数属于谁。
1.1、姜浩五大定律
- 通过函数名()直接调用:this指向window; 通过对象.函数名()调用的:this指向这个对象; 函数作为数组的一个元素,通过数组下标调用的:this指向这个数组; 函数作为window内置函数的回调函数调用:this指向window,setTimeout,setInterval等……; 函数作为构造函数,用new关键字调用时:this指向新new出的对象。
对于this指向谁,我们记住一句就行:谁最终调用函数,this就指向谁!
记住:
- this指向的永远只可能是对象! this指向谁,永远不取决于this写在哪!而是取决于函数在哪调用!!!
2、this的用法
准备了几个测试,快来看看你能否完全答对输出? 可先根据代码猜下输出内容,先自己思考一下印象才会更深哦 再在控制台复制代码回车查看对应的this输出内容
2.1 作为普通函数调用
// 在非严格模式下 var name = hello; function f1(){ console.log(this); console.log(this.name); name = this.name + world } f1(); console.log(this.name); // 在严格模式下 function f2() { "use strict"; console.log(this); } f2();
解析:
- 直接调用的情况下,不论是严格模式还是非严格模式,this的指向都是全局对象,在浏览器中这个值是window对象。 一个普通的函数调用时,在非严格模式下this指向window或global对象。严格模式下,this指向undefined。
2.2 作为对象的方法调用
var name = globalName var obj = { name : Yushia, getName : function(){ console.log(this.name); } } obj.getName(); var fun2 = obj.getName; fun2();
解析:
- 当函数作为一个对象里的方法被调用,this 指向该对象 把对象的方法赋值给一个变量,再调用这个变量,此时 this 指向了全局对象。给 fun2 赋值,其实是相当于:
var fun2 = function(){ console.log(this); }
可以看出,此时的 this 已经跟 obj 没有任何关系了。这时 fun2 是作为普通函数调用。
2.2.1 对象多层嵌套
function foo(){ console.log(this.name) } var shiny={ name:shiny, foo:foo } var red={ name:red, obj:shiny } red.obj.foo()
解析:
不管你的对象嵌套多深,this只会绑定为直接引用该函数的地址属性的对象
2.3 作为构造器调用
2.3.1 无返回值
function Person(n, a){ this.name = n; this.age = a; console.log(this); } var obj = new Person("Yushia", 18); console.log(obj.name); Person("Yushia", 18);
解析:
- 用 new 创建对象的时候调用了构造函数。 构造函数和普通函数的区别在于调用方式,而不是定义方式。 new关键字改变了函数内this的指向,使其指向刚创建的对象。
2.3.2 有返回值–返回一个对象
function Person(n, a){ this.name = n; this.age = a; return { name: "Lucy", }; } var obj = new Person("Yushia", 18); Person("Yushia", 18); console.log(obj.name); console.log(obj.age);
解析:
- 如果构造函数显式的返回一个对象,那么 this 则会指向该返回对象。
2.3.3 有返回值–返回基本数据类型非对象
function Person(n, a){ this.name = n; this.age = a; return "Lucy"; } var obj = new Person("Yushia", 18); Person("Yushia", 18); console.log(obj.name); console.log(obj.age);
解析:
- 构造函数的返回值如果是基本数据类型,那返回值和得到的对象无关
2.4 bind() 、apply() 、call() 调用
var name = "小王",age=18; var obj = { name: 小明, age:20, myFun:function(province,city){ console.log( this.name + "年龄" + this.age +",来自" + province + "省" + city +"市" ) ; } } var db = { name:"Yushia", age:18 } obj.myFun.call(db,福建,福州); obj.myFun.apply(db,[福建,福州]); obj.myFun.bind(db,福建,福州)(); obj.myFun.bind(db,[福建,福州])();
解析:
- call 、bind 、 apply 这三个函数的 第一个参数都是 this 的指向对象,第二个参数差别就来了: call 的参数是直接放进去的,第二第三第 n 个参数全都 用逗号分隔 ,直接放到后面 obj.myFun.call(db,‘成都’, … ,‘string’ )。 apply 的所有参数都必须放在一个 数组 里面传进去 obj.myFun.apply(db,[‘成都’, …, ‘string’ ])。 bind 除了返回是函数以外,它 的参数和 call 一样。
当然,三者的参数不限定是 string 类型,允许是各种类型,包括函数 、 object 等等!
2.5 setTimeout & setInterval
function Person() { this.age = 0; setTimeout(function() { console.log(this); }, 1000); } var p = new Person(); function Person2() { this.age = 0; setTimeout((function() { console.log(this); }).bind(this), 1000); } var p = new Person2();
解析:
- 对于延时函数(setTimeout & setInterval)内部的回调函数的this指向全局对象window 可以通过bind方法改变其内部函数的this指向
2.6 DOM 事件处理函数中的 this & 内联事件中的 this其
this 指向触发该事件的元素
<!-- 输出"Click Me" --> <input type="button" id="myBtn" value="Click Me" onclick="consloe.log(this.value)"> <script> var btn=document.getElementById(myBtn); btn.onclick=function(){ console.log(this.id); //"myBtn" } </script>
2.7 箭头函数中的 this
function Person() { this.age = 0; setTimeout(() => { console.log(this) }, 1000); } var p = new Person(); var obj = { a: () => { console.log(this) } } obj.a() var obj2 = { a: () => { console.log(this) } } obj2.a.call(123)
解析:
- 箭头函数会默认绑定外层this的值,所以在箭头函数中this的值和外层的this是一样的。 不能用call方法修改里面的this
2.8 闭包中的this
var name = "window"; var obj = { name: "Yushia", say:function(){ var that = this; console.log(this.name); return function(){ console.log(this.name); console.log(that.name); } } } obj.say()(); obj.say().call(obj);
解析:
因为闭包并不属于这个对象的属性或方法。所以在闭包中的 this是指向window.
- 闭包中的this指向的是window对象,this.name=window.name obj.say().call(obj) 这里通过call方法把this的指向换成了obj 在方法内部改变this指向,对象中的say方法中this是指向obj,使用that代替this,在闭包函数中写成that.name 那么结果指向obj
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/291096.html