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
}
。

浙公网安备 33010602011771号