this指向问题以及修改函数的this指向方法

1、什么是this

this表示对象
取决于函数调用

(this表示对象=>当前对象=>当前环境对象=>函数运行时环境对象)

this就是函数运行时所在的环境对象

(取决于函数调用=>不同场合,this有不同的值)

函数的不同使用场合,this有不同的值。

1、this永远指向对象
(JS中一切皆对象,window也是对象)
2、this指向取决于函数调用的位置
(this指向是不定的,无法在事先声明时就得知它的具体指向,因此只有在调用时才能得知它的指向)
3、this只能在函数体内部使用
(this是函数运行时,内部自动生成的一个对象(执行环境上下文,也称环境对象),this即函数内部环境对象本象,因此只能在函数内部使用)
4、箭头函数无视上述规则,且优先级最高
(箭头函数中this指向在声明处决定,指向作用域链的父级)

this指向问题以及修改函数的this指向方法_第1张图片

2、核心理解

场景优先级
箭头函数 > new > 显示绑定(call/apply/bind)> 隐式绑定(上下文对象obj) > 默认绑定(严格模式undefined,非严格为window)
注:
定时器setTimeout,setInterval中分两种情况,具体看下面例子
闭包或自执行函数被调用可以看做是接收了一个函数字符串,同样要看该字符串函数被调用的环境对象,具体看下面例子。

3、this指向详细例子

3.1 箭头函数中调用 箭头函数的this指向上一级环境对象

function fn() {
  setTimeout(() => {
    console.log(this.a);
  }, 1000);
}

var obj = {
  a: 20,
  fn,
};

fn.call(obj); // 20,这里可以理解为调用了obj.fn();

3.2 new实例调用 指向实例化出来的对象

function Person(name, age) {
  this.name = name;
  this.age = age;
}
const a = new Person('itachi', 18);
console.log( a.name ); // 这里new Person()构造函数内部的this指向了实例对象,
//即this=>a 所以this.name === a.name === 'itachi'

3.3 显示绑定(call/apply/bind) 绑定到指定的对象

可以参见箭头函数实例
var obj = {
  age: 20,
  fn:function (name) {
    console.log(this.name + '今年' + this.age + '岁')
  }
};
const a = { }
obj.fn.call( a , 'itachi'); // 执行了a.fn('itachi');'itachi'今年20岁
//这里可以理解为将obj中的this绑定到 a 
//让a拥有了obj中的方法fn(),并调用了 a.fn ('itachi');

3.4 隐式绑定(上下文对象obj)

function fn() {
  console.log(this.name);
}
var obj = {
  name: 'itachi'
};
// 调用 fn(..) 时把 this 绑定到 obj
obj.fn(); //itachi

3.5 默认绑定(严格模式undefined,非严格为window)

function fn() {
  console.log(this.a);
}
a = 10;
fn(); // 相当于window.fn()  输出10
function fn() {
  'use strict';
  console.log(this.a);
}
a = 10;
fn(); //相当于undefined.fn() 
//输出 TypeError: Cannot read property 'a' of undefined

3.6 定时器情况 定时器setInterval或setTimeout是window对象内置的一个方法

var obj = {
    fun:function(){
        return this ;
    }
}
​//此时还没执行fn,后面没跟(),即只是作为一堆字符串将其传了过去,执行的时候已经是1000ms以后了,这时是window.setInterval在执行
setInterval(obj.fn,1000);      // this指向window对象
//传入时就执行了,因此this指向的是obj对象
setInterval('obj.fn()',1000);  // this指向obj对象

3.7 函数作为闭包或自执行函数被调用 意味着这个函数不符合以上任意一种调用方式 因为闭包并不属于这个对象的属性或方法。所以在闭包中的this是指向window的

var name = “window”;
var obj={
    name: “Object”;
    getName: function(){
        return function(){
              return this.name;
        }
    }
};
var myobj = obj.getName(); //myobj接收到匿名函数(可以看做以字符串形式接收)
//myObj === 'function(){return this.name;}'  
console.log(myobj());  //  Window  相当于 return window.name
console.log(obj.myobj());  //  Object  相当于 return obj.name

3.8 在绑定事件中this指向—>当前事件对象

document.onclick = function () {
     console.log(this);
}

4、总结

this表示函数调用时的环境对象(执行上下文)
根据函数调用的不同场景,this指向也不同

在箭头函数中:this指向作用域链的父级环境  在定时器中this指向--->Window  
通过new实例化时:this指向新实例化出来的对象  在对象中this指向--->当前对象   在构造函数中this指向--->实例对象
通过call/apply/bind调用时:this将绑定到指定的对象 通过上下文(对象)调用时:this指向上下文(该对象)
通过一般函数内部调用时:严格模式this指向undefined,否则指向全局对象   普通函数this指向--->Window

5、修改this指向三张方法的格式以及注意事项:

call  apply:改变this的指向 ,call直接调用,而apply需要重新调用这个函数
call传参数:call(this指向的,参数1,参数2...);
apply传参数:apply(this指向的,[参数1,参数2...]);     --->apply传参数是一个数组
bind传参数:bind

5.1 强制修改this指向的调用格式:

fn1.call(obj);
 call() 方法的第一个参数必须是指定的对象,然后方法的原参数,挨个放在后面。
(1)第一个参数:传入该函数this执行的对象,传入什么强制指向什么;
(2)第二个参数开始:将原函数的参数往后顺延一位
函数名.call()

function fun() {
    console.log(this);  // 原来的函数this指向的是 Window
}
fun();
 
function fun(a, b) {
    console.log(this); // this指向了输入的 字符串call
    console.log(a + b);
}
//使用call() 方法改变this指向,此时第一个参数是 字符串call,那么就会指向字符串call
fun.call('call', 2, 3)  // 后面的参数就是原来函数自带的实参
fn1.apply(obj);
apply() 方法的第一个参数是指定的对象,方法的原参数,统一放在第二个数组参数中。
(1)第一个参数:传入该函数this执行的对象,传入什么强制指向什么;
(2)第二个参数开始:将原函数的参数放在一个数组中 
用法: 函数名.apply()
function fun() {
    console.log(this);  // 原来的函数this指向的是 Window
}
fun();
 
function fun(a, b) {
    console.log(this); // this指向了输入的 字符串apply
    console.log(a + b);
}
//使用apply() 方法改变this指向,此时第一个参数是 字符串apply,那么就会指向字符串apply
fun.apply('apply', [2, 3])  // 原函数的参数要以数组的形式呈现```
fn1.bind(obj)();
bind() 方法的用法和call()一样,直接运行方法,需要注意的是:bind返回新的方法,需要重新
调用
是需要自己手动调用的
用法: 函数名.bind()
function fun() {
    console.log(this);  // 原来的函数this指向的是 Window
}
fun();
 
function fun(a, b) {
    console.log(this); // this指向了输入的 字符串bind
    console.log(a + b);
}
//使用bind() 方法改变this指向,此时第一个参数是 字符串bind,那么就会指向字符串bind
let c = fun.bind('bind', 2, 3);
c(); // 返回新的方法,需要重新调用
// 也可以使用下面两种方法进行调用
// fun.bind('bind', 2, 3)();
// fun.bind('bind')(2, 3);

5.2 强制修改this指向的传参语法:


fn1.call(obj, 1, 2);
 
fn1.apply(obj, [3, 4]);
 
fn1.bind(obj)(5, 6);    // bind传参在react框架用的比较多些

你可能感兴趣的:(javascript,开发语言,ecmascript)