javascript基础 this指向
this指向:this永远指向一个对象;this的指向完全取决于函数调用的位置;
场景1:在全局环境中调用,this 指向 window对象
var a = 'a' function foo() { console.log(this.a) } foo() // "a"
// this 指向 window对象 (小写,大写的Window是构建函数) window 是Window 的实例
// window instanceof Window true
场景2:以对象的属性方法形式调用,this 指向方法所属的那一级对象本身
function foo() {console.log(this.a)} var obj1 = { a: 1, fn: foo, } var obj2 = { a: 2, fn: foo, } var obj3 = { a: 1, o2: obj2, } obj1.fn() // this 指向 obj1 obj3.o2.fn() // this 指向 obj3.o2 即 obj2
场景3:事件绑定中的 this。也分为两种情况:函数调用this指向window对象;行内调用 this 指向 当前节点对象。
// 函数调用 <input type="button" value="按钮" onclick="clickFun()" /> // 行内调用 <input type="button" value="按钮" onclick="console.log('this;',this)" /> // 如果不是一个函数调用,直接在当前节点对象环境下使用this,那么显然this就会指向当前节点对象; function clickFun() { console.log('this;', this) // 此函数的运行环境在全局window对象下,因此this指向window; }
场景4:构建函数中的this。 首先要理解 构建函数 调用的过程;所以 this 总是指向 构建的对象实例本身。
function Pro() { this.x = '1' this.y = function () {}
console.log(this) // Pro {x: '1', y: ƒ} } var p = new Pro() // new 构造函数的过程 // 1.创建一个空对象; // 2.将空对象的原型(__proto__)指向构造函数的 prototype // 3.将构造函数中的 this 指向该空对象 // 4.执行代码赋值 给空对象的属性赋值; // 5.返回本对象地址
场景5:定时器 setInterval ,setTimeout 。这两本身是 window 的内置属性,接受两个参数,第一个参数允许是一个函数或者是一段可执行的 JS 代码,第二个参数则是执行前面函数或者代码的时间间隔;
var obj = { fun: function () { console.log("this:",this) }, } setInterval(obj.fun, 1000) // this指向window对象 setInterval('obj.fun()', 1000) // this指向obj对象 // 在上面的代码中,setInterval(obj.fun,1000)的第一个参数是obj对象的fun , 因为 JS中函数可以被当做值来做引用传递,实际就是将这个函数的地址当做参数 传递给了setInterval 方法,
// 换句话说就是 setInterval 的第一参数接受了一个函数,那么此时1000毫秒后,函数的运行就已经是在window对象下了,也就是函数的调用者已经变成了window对象,所以其中的this则指向的全局window对象; // 而在setInterval('obj.fun()',1000) 中的第一个参数,实际则是传入的一 段可执行的 JS代码;1000毫秒后当 JS 引擎来执行这段代码时,则是通过 obj 对象来找到 fun函数并调用执行,
// 那么函数的运行环境依然在 对象 obj 内,所以函数内部的this也就指向了 obj 对象;
场景6:函数对象的call(), apply()方法,绑定。this 指向绑定的对象
function fun(){console.log(this.name)) var obj = {name:"aaa"} fun.call(obj) // this 指向 obj // call和apply的作用一致,区别仅仅在函数实参参数传递的方式上; // call方法使用的语法规则 函数名称.call(obj,arg1,arg2...argN); // 参数说明: obj:函数内this要指向的对象, arg1,arg2...argN:参数列表,参数与参数之间使用一个逗号隔开; // apply方法使用的语法规则 函数名称.apply(obj,[arg1,arg2...,argN]) // 参数说明: obj :this要指向的对象 [arg1,arg2...argN] : 参数列表,要求格式为数组 var obj={name:"xxx"} function foo(num){this.age = num;console.log("this:",this)} var fooBO = foo.bind(obj) fooBO(18) // this: {name: 'xxx', age: 18} var fxx = foo.bind(obj,18) fxx(19) // this: {name: 'xxx', age: 18} // 接收参数与call相同。 // 函数调用后返回一个 匿名函数,需要再次调用
补充:常见面试题 手写call bind
// 1.所有函数都可以掉用 // 2.可以接收多个参数,至少有1个 // 3.第一个参数就是我们要去改变的this,从第二个开始是函数本身的参数 // 4.call 还有返回值 返回值是函数的执行结果 Function.__proto__.newCall = function (obj) { let thisObj = obj || window thisObj.fun = this // this 指向getInfo let arg = [...arguments] arg.splice(0, 1) let returnObj = thisObj.fun(...arg) delete thisObj.fun return returnObj } // 手写一个 bind 方法 // 1. 可以接收多个参数,至少有1个 // 2. 返回值是函数的执行结果 // 3. 返回一个函数可以作为构造函数使用,此情况下 this 失效 Function.__proto__.newBind2 = function (obj) { // 可能会只拿到一部分参数 var _this = this, arr = Array.prototype.slice.call(arguments, 1) // 也可能会只拿到一部分参数 // 调用时拿到当前函数 getInfo 的返回值 var newFun = function () { var arr2 = Array.prototype.slice.call(arguments, 0) var list = arr.concat(arr2) // 作为构造函数使用,此情况下 this 失效 if (this instanceof newFun) { return _this.newCall(this, ...list) } else { return _this.newCall(obj, ...list) } } return newFun }
。