JS-关于this指向及其改变方法call\apply\bind

什么是this?

  1. 在js中,this是一个指针型变量,它动态指向当前函数的运行环境。
  2. 在不同的场景中调用同一个函数,this的指向也可能会发生变化,但是它永远指向其所在函数的真实调用者;如果没有调用者,就指向全局对象window。

this有以下6类场景分类:全局、函数内、对象内、构造函数、箭头函数、原型链;

1、全局作用域的this指向

在全局作用域下,this始终指向全局对象window,无论是否是严格模式

congsole.log()完整的写法是window.console.log(),window可以省略,window调用了console.log()方法,所以此时this指向window。

2、普通函数内this指向

函数内的this指向分为2种情况,严格模式、非严格模式;

严格模式:使用者对代码的的调用必须严格的写出被调用的函数的对象,不可以有省略或者说简写;
function aa(){
    name:'hyy',
    say:function(){
        console.log('hello world',this)
    }
}

aa() // undefined  因为没有写出被调用的函数对象,不能简写
window.aa() // window

非严格模式:
aa() // window
window.aa() // window

3、对象内this指向

对象内的this指向,谁调用方法就指向谁;多层嵌套的情况下,找最近的调用对象。

4、构造函数的this指向

关于this,指向new创建出来的新实例上。

5、箭头函数的this指向

箭头函数:this指向于函数作用域所用的对象,向上寻找父级、最近的this。

箭头函数的重要特征:箭头函数中没有this和arguments。

箭头函数没有自己的this指向,它会捕获自己定义所处的外层执行环境,并且继承这个this值,指向当前定义时所在的对象。箭头函数的this指向在被定义的时候就确定了,之后永远都不会改变。即使使用call()、apply()、bind()等方法改变this指向也不可以。

6、原型链中的this

**在原型链继承当中,this永远指向它原本的对象,**而不是通过原型链上找到的所属对象。

改变this指向的方法

call 、bind 、apply都可以改变this的指向;this的指向只能是复杂类型。

1、call(1.调用fn,2.改变this指向);

arr.call() 不传任何参数,实际是把参数设置为window

arr.call(基本类型),指向对应的基本类型包装类型的对象,如3 (new Number(3))===> Number{3} ;

函数.call(需要修改的this指向,实参列表) call(a,b,c)//一次性的
细节:如果什么都没传,或者是null或undefined,那么this的指向一定是window;
	this的指向只能是复杂类型,如果传的是基本类型也会包装成负责类型;
function Person(name,age){
     this.name = name
     this.age = age
  }
Person.prototype.sayHi = function (){
     console.log(`我的名字是${this.name},我的年龄是${this.age}`)
  }

let person1 = new Person('小明',18)
let person2 = new Person('老王',50)

person1.sayHi() // 我的名字是小明,我的年龄是18
person1.sayHi.call(person2) //我的名字是老王,我的年龄是50
person2.sayHi() //我的名字是老王,我的年龄是50
// arr1.call(arr2) ,arr1的this指向arr2
// 利用call借用数组方法
    let arr = {  // 伪数组
        0:'1',
        1:'2'
    }
    Array.prototype.push.call(arr,'3') 
    Array.prototype.join.call(arr,"")
    [].prototype.sort.call(arr,function(a,b){return a-b})

// 利用call借用string方法
    let arr = [1,2,3,45,5]
    String.prototype.substr.call(arr,0,3)

// 利用call借用构造函数继承,以及“完整继承”如何实现
        function Person(name,age){
            this.name = name
            this.age = age
        }

        Person.prototype.sayHi = function(){
            console.log(`我叫${this.name},年龄${this.age}`)
        }

        function Student(name,age){
            Person.call(this,name,age)
            stud = function(){
                console.log('我是学生')
            }
        }

        let s1 = new Student('hyy',18)
        // s1.sayHi() // 报错,因为这里只继承了构造函数Person,于原型链无关
        // 完全继承,涉及混入,原型继承
        for (let key in Person.prototype){
            Student.prototype[key] = Person.prototype[key]
        }
        s1.sayHi()
2、apply(1.调用fn,2.改变this指向)

apply语法其实于call一样,区别不过传参形式不一样罢了;

函数.apply(需要修改的this指向,实参数组/伪数组) apply(a,[b])//一次性的
细节:传入的参数,必须是数组或伪数组
// 求数组最大最小值,以前用for循环
 let arr = [1,2,445,6756,234,0]
 // let max = Math.max(...arr)
 // let min = Math.min(...arr)
 let max = Math.max.apply(arr,arr)
 let min = Math.min.apply(arr,arr)
 console.log(max,min)
3、bind**(1.不调用fn,2.改变this指向,3.返回一个新的函数)

bind语法与call一模一样,区别在与立即执行还是等待执行,call是直接改变函数的this指向,而bind是生成一个新的函数,该函数改变指向

let newFn = Fn.bind(需要修改的this指向,实参列表) //永久了
细节:如果初始就传入实参列表了,以后实参就固定了无法修改;
        function Person(name,age){
           this.name = name
           this.age = age
        }
        Person.prototype.sayHi = function (){
            console.log(`我的名字是${this.name},我的年龄是${this.age}`)
        }

        let person1 = new Person('小明',18)
        let person2 = new Person('老王',50)

        person1.sayHi() // 我的名字是小明,我的年龄是18
        person1.sayHi.bind(person2)() //我的名字是老王,我的年龄是50 (看这里是需要调用才会执行的)
        person1.sayHi() //我的名字是小明,我的年龄是18 (产生了新的函数所以这里不影响原来的函数)
//案例:修改定时器的指向
// <button id='get'>获取验证码</button>
Document.querySelector('#id').onclick = function(){
let sec = 59;
    this.innerHTML = '还有59秒'// 这里的this是dom元素
    this.disabled = true;

let timeId = setInterval(function(){
    sec--
    this.innerHTML = '还有' + sec + '秒'if(sec == 0){
        clearInterval(timeId);
        this.innerHTML = '获取验证码'// 定时器的this是window,所以这里肯定报错
        this.disabled = false;
    }
},1000) 
}
// 目的:把定时器的this指向dom的this
Document.querySelector('#id').onclick = function(){
let sec = 59;
    this.innerHTML = '还有59秒'// 这里的this是dom元素
    this.disabled = true;

    let fn = function(){
    sec--
    this.innerHTML = '还有' + sec + '秒'if(sec == 0){
        clearInterval(timeId);
        this.innerHTML = '获取验证码'// 定时器的this是window,所以这里肯定报错
        this.disabled = false;
    }
}
    let newFn = fn.bind(this);
let timeId = setInterval(newFn,1000) 
}
//结果
Document.querySelector('#id').onclick = function(){
let sec = 59;
    this.innerHTML = '还有59秒'// 这里的this是dom元素
    this.disabled = true;

let timeId = setInterval((function(){
    sec--
    this.innerHTML = '还有' + sec + '秒'if(sec == 0){
        clearInterval(timeId);
        this.innerHTML = '获取验证码'// 定时器的this是window,所以这里肯定报错
        this.disabled = false;
    }
}).bind(this),1000) 
}
  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值