R002-これの指し方とこれの指し方の変更について(詳しい説明)

1. これは問題を示しています

関数の呼び出し方法の違いによって方向が決まり、通常は関数の呼び出し元を指します。

1. 世界的に

グローバルに、これは常に window オブジェクトを指します。

// 全局下, this始终指向window对象
console.log(this);  // window   相当于window.console.log(this);  window

2.関数内

(1) 通常の関数として呼び出される場合

非厳密モードでは、これはウィンドウを指します

厳密モードでは、これは未定義を指します

// 函数中 this 关键字的指向问题
// 1. 作为函数被调用
//  (1) 非严格模式下, 直接被调用   this指向Window
function fun(){
  console.log('非严格模式下, 直接被调用==>',this);   //非严格模式下, 直接被调用==> Window {window: Window, self: Window, document: document, name: '', location: Location, …}
}
fun()   //  Window

//  (2)在函数中,严格模式下,直接调用函数,  this指向undefined
function strictFun(){
  'use strict'
  console.log('严格模式下, 直接被调用==>',this);    //严格模式下, 直接被调用==> undefined
}
strictFun()   //  undefined

(2) メソッドとして呼び出す場合(オブジェクトメソッド)

これはメソッドの所有者を指します

オブジェクトの内部メソッドの this は、それを呼び出す人を指します。

// 2. 作为方法被调用, this指向方法拥有者(当多层对象嵌套时, this指向被调用函数最近的对象)      当函数作为对象的某个属性时, 可称这个函数为方法
// 对象内部方法的this 谁调用就指向谁
let obj = {
  uname: 'mm',
  eat1(){
    console.log('eat1===>', this);
  },
  eat2: function(){
    console.log('eat2==>', this);
  },
  eat3: ()=>{
    console.log('eat3==>',this);
  },
  objjj: {
    name: 'aaa',
    eat4(){
      name: 'bbb'
      console.log(this.name);  // aaa
      console.log('内层对象this',this);
    }
  }
}
obj.eat1()   // obj 
obj.eat2()   // obj 
obj.eat3()   // window    箭头函数没有this, 他的this指向来源于父级this指向
obj.objjj.eat4()  //  objjj    被调用函数最近的对象

(3) コンストラクタとして呼び出される場合

通常はインスタンス化されたオブジェクトを指します

// 3. 作为构造函数来使用, 通常指向实例化对象
function User(){
  this.uname = 'mmm';
  this.age = 21;
  console.log('构造函数User中的this===>',this);
}
let mm = new User()
console.log('mm===>',mm);  // {uname: 'mmm', age: 21}

補充: 

コンストラクターが new の処理中に何が起こるか:

  1. 空のオブジェクトを作成する

  1. 空のオブジェクトはこのパラメーターとしてコンストラクターに渡され、コンストラクターのコンテキストになります (例: コンストラクター内の this を mm に置き換えます)

  1. 新しく構築されたオブジェクトは new 演算子の戻り値として返されます (コンストラクターが返されたオブジェクトを表示するときに例外が発生します。コンストラクター内にオブジェクト型の戻り値があるかどうかを確認してください)。

// 构造函数内部有返回值,为非对象类型,  使用new关键字后,会走正常实例化的流程,将tt传递给this
function User1(){
  this.uname = 'ttt';
  this.age = 22;
  console.log('构造函数User1中的this===>',this);
  return 1;
}
let tt = new User1()   
console.log('tt===>', tt); // {uname: 'ttt', age: 22}
// 构造函数内部有返回值,且为对象类型, new关键字创建对象后, 会直接返回构造函数内部的对象
function User2(){
  this.uname = 'ttt2';
  this.age = 22;
  console.log('构造函数User2中的this===>',this);
  return {
    n: 'haha'
  }
}
let tt2 = new User2() 
console.log('tt2===>', tt2);  //{n: 'haha'}

(4) アロー関数内

this ポイントは、親の this ポイント (非アロー関数の親) から取得されます。

アロー関数には this と引数はありません。 this ポイントは親の this ポイントから取得され、定義時に決定され、call()、apply()、bind を使用した場合でも、その後変更されることはありません。 () などのメソッドで方向を変更することはできません

// 箭头函数   箭头函数中没有this和arguments, 他的this指向来源于父级this指向,且被定义的时候就确定了,之后永远都不会改变,即使使用call()、apply()、bind()等方法改变this指向也不可以
let fn = ()=>{
  console.log(this);
}
fn()   // window

(5) 関数を即時実行する

これはウィンドウオブジェクトを指します

// 立即执行函数   this指向window对象
;(function(){
  console.log('立即执行函数==>',this);   //window
}())

(6) タイマー機能の場合

これはウィンドウオブジェクトを指します

// 定时器函数中  this指向window对象
setTimeout(function(){
  console.log('定时器函数===>',this);
}, 1000)

3. イベントバインディングメソッド内

イベント バインディング メソッドでは、イベントにバインドされたオブジェクトを指します。

  <!-- 事件绑定方法中, this指向绑定事件的对象  -->
  <button>事件绑定方法</button>
  <script>
    document.querySelector('button').addEventListener('click',function(){
      console.log('事件绑定方法===>',this);   // <button>事件绑定方法</button>
    })
  </script>

4. クロージャー内

// 闭包中的this
const obj = {
  name: '内---mm',
  getName: function () {
    return this.name
  },
}
console.log('getName===>', obj.getName()) // 内---mm
const getNameFun = obj.getName
// getNameFun 是一个函数  调用时,没有其他调用者,那么调用者即为Window对象, const声明的变量在window上没有,故为undefined,  若为var声明则为var声明的变量值
console.log('getNameFun==>', getNameFun()) //undefined

const obj1 = {
  name: '内1111---mm',
  getName: function () {
    return function () {
      return this.name
    }
  },
}
// obj1.getName获得一个函数function(){ return function(){ return this.name }, ()执行一次,又得到一个函数function(){return this.name},再()执行返回this.name, 此时没有其他调用者调用
console.log('getName1===>', obj1.getName()()) //undefined
const getNameFun1 = obj1.getName()
console.log('getNameFun1==>', getNameFun1()) //undefined

const obj2 = {
  name: '内1111---mm',
  getName: function () {
     //保存环境,保存this, 保存当前调用者   that常驻内存
    const that = this 
    // 闭包    函数套函数, 内部函数可访问函数体外的变量
    return function () {
      return that.name
    }
  },
}
console.log('getName2===>', obj2.getName()()) //内1111---mm
const getNameFun2 = obj2.getName()
console.log('getNameFun2==>', getNameFun2()) //内1111---mm

2. 方向を変える

JavaScript は特に、関数内で this のポインティングの問題に対処するいくつかの関数メソッド (多くの場合、bind()、call()、apply()) を提供します。

1. call() メソッド

fun.call(thisArg, arg1, arg2, ...)

  • すぐに実行する

  • thisArg オプション パラメータ。非厳密モードで関数の実行時に使用される this 値。null または未定義として指定された場合、自動的にグローバル オブジェクトに置き換えられます。

  • arg1、arg2 で指定されたパラメータのリスト

  • オブジェクト (呼び出し可能関数) を呼び出すと、関数のこの時点を変更できます。

  • 戻り値: メソッドの戻り値。戻り値がない場合は未定義を返します。

  • アプリケーション: 継承の実装

// call(thisArg, arg1, arg2...)  thisArg可选参数, 函数运行时使用的this值, arg1,arg2指定的参数列表
function callThis(sex){
  console.log(`name: ${this.name},sex: ${sex}`);   // name: mm,sex: girl
  return this.name   
}
let person1 = {name:'mm'}
let res1 = callThis.call(person1,'girl')
console.log('res1===>', res1);   // mm (函数内部自身的有返回值,返回了this.name,  若没有会返回undefined)

// 非严格模式下,则指定为null或undefined时会自动替换为全局对象
var num = 1
function showNum(){
  console.log('num===>', this.num);
}
showNum.call(undefined)   // 1 
function showNum1(){
  console.log('num===>', this.num);
}
showNum1.call(null)   // 1

// 严格模式
"use strict";
var number = 2 
function showNum2(){
  console.log('number===>', this.number);
}
showNum2.call(undefined)   //  报错    Uncaught TypeError: Cannot read properties of undefined (reading 'number')

2. apply() メソッド

fun.apply(thisArg, [argsArray])

  • すぐに実行する

  • thisArg オプション パラメータ。非厳密モードで関数の実行時に使用される this 値。null または未定義として指定された場合、自動的にグローバル オブジェクトに置き換えられます。

  • 引数は配列 [argsArray] の形式でなければなりません

  • 戻り値: メソッドの戻り値。戻り値がない場合は未定義を返します。

  • 呼び出し可能な関数。関数のこの時点を変更できます。

  • 用途: 多くの場合、配列に関連します。たとえば、数学オブジェクトを使用して配列の最大値と最小値を取得します。

// apply()  与 call()相同, 只是参数需要传递一个数组
function applyThis(sex){
  console.log(`name: ${this.name},sex: ${sex}`);   // name: tt,sex: boy
  return this.name   
}
let person2 = {name:'tt'}
let res2 = callThis.call(person2,['boy'])
console.log('res2===>', res2);   // tt

3.bind()メソッド

fun.bind(thisArg, arg1, arg2, ...)

  • 新しい関数が作成され、新しい関数が呼び出されたときに実行されます。

  • thisArg オプション パラメーター。非厳密モードで関数が実行されているときに使用される this 値。null または未定義として指定されている場合、バインドされた関数の構築に new 演算子が使用されている場合、自動的にグローバル オブジェクトに置き換えられます。 、この値は無視されます

  • arg1、arg2 は、ターゲット関数が呼び出されるときにパラメータ リストにあらかじめ設定されているパラメータであり、ターゲット パラメータが呼び出されるときにパラメータが渡され、パラメータの数は置き換えられるのではなく増加されます。

  • 戻り値: 指定された this 値と初期パラメータを持つ元の関数のコピー (指定された this 値と初期化パラメータから変換された元の関数のコピーを返します (元の関数が this を変更した後に生成された新しい関数を返します))

  • 関数は呼び出されず、関数の内部の this ポイントは変更できます。

  • アプリケーション: タイマー内の this ポインターを変更するなど。

// bind()   原函数的拷贝,并拥有指定的this值和初始参数
function bindThis(sex){
  console.log(`name: ${this.name},sex: ${sex}`);    
  return this.name   
}
let person3 = {name:'kkong'}
let res3 = bindThis.bind(person3,'boy')
console.log('res3===>', res3);   
/* res3===>   ƒ bindThis(sex){
   console.log(`name: ${this.name},sex: ${sex}`);  
   return this.name   
} */
// res3是个函数  原函数的拷贝,并拥有指定的this值和初始参数
res3()   //name: kkong,sex: boy
// 使用new运算符构造绑定函数, 则忽略thisArg这个可选参数
new res3()   // name: undefined,sex: boy 

// 当目标参数调用时传入参数,会增加参数数量而不是替换
function Arg(){
  console.log(Array.from(arguments).join());
}
var result1 = Arg.bind()
result1()   //   空白
var result2 = Arg.bind(undefined,1,2)
result2()      //1,2
var result3 = Arg.bind(undefined,3,4)
result3(5,6)   //3,4,5,6
const a = new result3(7,8,9)  //3,4,7,8,9
const b = new Arg()  // 空白
            // 改变函数内this指向
            // 1. call()   可调用函数,可改变函数内this指向.  主要作用: 实现继承
            function Father(uname){
                this.uname = uname;
            }
            function Son(uname, uage){
                Father.call(this,uname,uage);  //调用函数Father,将其this修改为Son中的this,并且添加uage属性    应用: 实现继承
            }
            // 2. apply()   可调用函数,可改变函数内this指向     参数必须是数组(伪数组)       应用: 利用apply借助数学内置对象求最大/小值
            var o = { };
            function fn(arr){ 
                console.log(arr); 
            }
            fn.apply(o,['pink']);
            var arr1 = [1,3,5,2,4];   //求数组最大/小值
            console.log(Math.max.apply(null, arr1));//不需改变this指向写null
            // 3. bind()   绑定
            var fn1 = fn.bind(o);   //不调用原函数, 可改变原函数内部this指向
            fn1;          //返回原函数改变this之后产生的新函数
            // 点击按钮后禁用,三秒后开启使用         定时器函数不需要立即执行,改变this指向用bind
            var btn = document.querySelector('button');
            btn.onclick = function(){
                this.disabled = true;  //this指向btn  按钮禁用
                setInterval(function(){
                    this.disabled = false;   //开启按钮  定时器中this指向window
                }.bind(this),3000);    //此处this指向btn对象
            }

おすすめ

転載: blog.csdn.net/qq_54379580/article/details/129540559