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
}

 

。  

posted @ 2022-11-11 18:26  前端-通天  阅读(20)  评论(0编辑  收藏  举报