Heim  >  Artikel  >  Web-Frontend  >  Wohin weist JavaScript?

Wohin weist JavaScript?

青灯夜游
青灯夜游Original
2021-06-15 16:27:353807Durchsuche

Dies zeigt auf: 1. Gewöhnliche Funktionen oder als Objektattribute, die auf das Fensterobjekt zeigen. 2. Bei der Ereignisbindung zeigt es auf das Element des gebundenen Ereignisses. 3. Im Konstruktor zeigt es auf die Instanz der Klasse. 4. Zeigen Sie in der Pfeilfunktion auf „This“ im nächstgelegenen übergeordneten Kontext. 5. Zeigen Sie in „call/apply/bind“ auf den ersten übergebenen Parameter.

Wohin weist JavaScript?

Die Betriebsumgebung dieses Tutorials: Windows7-System, Javascript-Version 1.8.5, Dell G3-Computer

Der this-Zeiger in JavaScript ist unterteilt in folgende Situationen: JavaScriptthis指向分为以下几种情况:

  • 普通函数或作为对象属性
  • 事件绑定
  • 构造函数
  • 箭头函数
  • call/apply/bind指定

下面我们来进行一一介绍

普通函数或作为对象属性

this取决于方法执行前面是否有“点”,有“点”的话,“点”前面是谁this就是谁,如果没有点的话,this指向window

const fn = function () {
  console.log(this);
};

const obj = { name: 'OBJ', fn };

fn();

obj.fn();

const fn1 = obj.fn;
fn1();

answer:

1. window
2. {name: 'OBJ', fn: function() {console.log(this)}} // obj
3. window

可以看到函数作为对象的属性被调用的时候,其this指向调用该函数的对象,否则其this指向window

事件绑定

在进行事件绑定的时候,事件绑定函数中的this是绑定事件的元素:

// 假设页面中有id为button的button元素
// var x = 100;
window.x = 100;
const fn = function () {
  console.log(this.x);
};
const obj = { x: 200, fn };
const $button = document.getElementById('button');
$button.x = 300;

obj.fn();
const fn1 = obj.fn;
fn1();

$button.addEventListener('click', fn);
$button.addEventListener('mouseenter', obj.fn);

$button.addEventListener('mouseleave', function () {obj.fn();});

answer:

1. 200
2. 100
3. 点击button时:300
4. 鼠标移入button时:300
5. 鼠标移出时:200

但是需要注意的是,这里我们是在用户点击时,浏览器帮我们将点击事件的this指向绑定该事件的DOM元素。如果通过代码来触发对应的事件的话,我们可以通过call/apply/bind来指定其this

$button.click.call() // this为window,打印结果为100

构造函数(new Fn)

构造函数(new Fn)执行,函数中的this是当前类的实例,这是new关键字帮我们做到的:

var x = 100;
const Fn = function () {
  this.x = 200;
  console.log(this.x);
};

const fn = new Fn();

answer:

1. 200

箭头函数

箭头函数中没有自身的this,所用到的this都是其最近父级上下文中的this

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

const obj = { x: 100, fn };

obj.fn();

answer:

1. {x:100, fn: function() {...}} // obj
2. window
3. {x:100, fn: function() {...}} // obj

call/apply/bind改变this指向

call/apply/bind传入的第一个参数即为函数的this

var x = 100;
const obj = { x: 200, y: 200 };
const fn = function () {
  console.log(this.x);
};

fn();
fn.call(obj);
fn.apply(obj);

const fixedThisFn = fn.bind(obj);
fixedThisFn();

answer:

1. 100
2. 200
3. 200
4. 200
  • call在执行时,第一个参数为this指向,之后的参数为fn执行时的参数
  • apply在执行时,第一个参数为this指向,之后的参数为fn执行时的参数组成的数组,数组的每一项会和fn的每一个参数进行对应
  • bind在执行时,第一个参数为预先传入this指向,之后的参数为实际调用fn前预先传入的参数,返回值为一个函数fixedThisFnfixedThisFn内部会调用fn并指定其this指向

为了更深入的理解call/apply/bind是如何改变函数中this指向的,下面我们分别模拟实现这三个函数

call/apply/bind源码实现

根据前面的介绍,我们知道:当函数作为对象属性被调用时,this指向调用该函数的对象

const obj = { x: 100, fn () {console.log(this);} };
obj.fn(); // {x: 100, fn: function() {...}} => obj

利用JavaScript这个特性,我们可以将执行的函数作为call/apply的第一个参数context的属性,然后通过context来调用该属性对应的函数,函数的this便指向了context

call的源码模拟如下:

Function.prototype.myOwnCall = function (context, ...args) {
  const uniqueKey = new Date().getTime();
  // this为调用call方法的函数
  context[uniqueKey] = this;
  // 作为对象的方法被对象调用,this指向该对象context
  const result = context[uniqueKey](...args);
  delete context[uniqueKey];
  return result;
};

到这里,有的小伙伴可能已经发现了,如果call/apply传入的context不是对象呢?

首先我们看下mdncall方法的第一个参数的描述:

语法:function.call(thisArg, arg1, arg2, ...)
* thisArg
  可选的。在function函数运行时使用的this值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定nullundefined时会自动替换为指向全局对象,原始值会被包装

接下来,我们对myOwnCall方法的第一个参数做如下处理:

function translateToObject (context) {
  // 可以通过 == 进行判断 context == null
  // null == undefined  => 2个等号是成立的
  // null,undefined => window
  if (typeof context === 'undefined' || context === null) {
    context = window;
  } else if (typeof context === 'number') { // 原始值转换为包装对象
    context = new Number(context);
  } else if (typeof context === 'string') {
    context = new String(context);
  } else if (typeof context === 'boolean') {
    context = new Boolean(context);
  }
  return context;
}

myOwnCall方法中调用该函数:

Function.prototype.myOwnCall = function (context, ...args) {
  context = translateToObject(context);
  const uniqueKey = new Date().getTime();
  // this为调用call方法的函数
  context[uniqueKey] = this;
  // 作为对象的方法被对象调用,this指向该对象context
  const result = context[uniqueKey](...args);
  delete context[uniqueKey];
  return result;
};

apply的实现与call

  • Gewöhnliche Funktion oder als Objekteigenschaft
  • Ereignisbindung
  • Konstruktor
  • Pfeilfunktion
  • call/apply/bindSpezifikation
Lassen Sie uns sie einzeln vorstellen🎜

Gewöhnliche Funktionen oder als Objektattribute

🎜this hängt davon ab, ob ein „Punkt“ vor der Methodenausführung steht. Wenn ein „Punkt“ vorhanden ist, wird derjenige, der vor dem „Punkt“ steht, this sein . Wenn kein Punkt vorhanden ist, zeigt this auf <code>window🎜
Function.prototype.myOwnBind = function (context, paramsArray) {
  context = translateToObject(context);
  const uniqueKey = new Date().getTime();
  // this为调用call方法的函数
  context[uniqueKey] = this;
  // 作为对象的方法被对象调用,this指向该对象context
  const result = context[uniqueKey](...paramsArray);
  delete context[uniqueKey];
  return result;
};
🎜Antwort:🎜
Function.prototype.myOwnBind = function (context, ...outerArgs) {
  const fn = this;
  return function (...innerArgs) {
    return fn.call(context, ...outerArgs, ...innerArgs);
  };
};
🎜Sie können sehen, dass eine Funktion als Eigenschaft eines Objekts aufgerufen wird this zeigt auf das Objekt, das die Funktion aufruft, andernfalls zeigt this auf window🎜

Ereignisbindung

🎜Wenn die Ereignisbindung durchgeführt wird, ist this in der Ereignisbindungsfunktion das Element, das das Ereignis bindet: 🎜
Function.prototype.myOwnBind = (context, ...outerArgs) => (...innerArgs) => this.call(context, ...outerArgs, ...innerArgs);
🎜Antwort:🎜
function fn1 () {console.log(1);}
function fn2 () {console.log(2);}
fn1.call(fn2);

fn1.call.call(fn2);

Function.prototype.call(fn1);
Function.prototype.call.call(fn1);
🎜Aber es sollte beachtet werden, dass hier, wenn die Wenn der Benutzer klickt, hilft uns der Browser dabei, die thisPoints des Klickereignisses auf das DOM-Element zu übertragen, an das das Ereignis gebunden ist. Wenn das entsprechende Ereignis durch Code ausgelöst wird, können wir seinen this🎜
1. 1
2. 2
3. 什么都不输出
4. 1

Konstruktor ( new Fn)

🎜 angeben Der Konstruktor (new Fn) wird in der Funktion als Instanz der aktuellen Klasse ausgeführt. Das Schlüsselwort new hilft uns dabei it:🎜
// 1. 首先会将Function.prototype.call作为一个函数来执行它原型上的call方法
// 所以call方法内部:
//    this => Function.prototype.call
//    context => fn1
// 通过对象的属性来执行方法改变this指向
//    fn1[uniqueKey] = this(Function.prototype.call)
//    fn1[uniqueKey]() // 执行 Function.prototype.call方法,但是this是context
// 2. 在this为fn1的情况下执行Function.prototype.call方法
// 所以call方法内部:
//    this => fn1
//    context => window
// 通过对象的属性来改变this指向
//    window[uniqueKey] = fn1
//    window[uniqueKey]() // 执行fn1(),但是this是window
🎜Antwort:🎜rrreee

Pfeilfunktion

🎜Die Pfeilfunktion hat keinen eigenen this, den this Der verwendete Code ist <code>this im nächsten übergeordneten Kontext🎜rrreee🎜answer:🎜rrreee

call /apply/bindChange this zeigen auf

🎜Der erste Parameter, der für call/apply/bind übergeben wird, ist die Funktion this:🎜rrreee🎜answer:🎜rrreee
  • Wenn call ausgeführt wird, zeigt this auf den ersten Parameter. Die folgenden Parameter sind die Parameter, wenn fn ist ausgeführt.
  • Wenn apply ausgeführt wird, zeigt this auf den ersten Parameter. Die nachfolgenden Parameter sind ein Array, das aus Parametern besteht, wenn fn wird ausgeführt. Jedes Element im Array entspricht jedem Parameter von fn
  • bind</code.></li> </ul> ausgeführt wird, ist der erste Parameter Der im Voraus übergebene Parameter this und die nachfolgenden Parameter sind die Parameter, die im Voraus vor dem tatsächlichen Aufruf von fn übergeben wurden. Rückgabe Der Wert ist eine Funktion fixedThisFncode>. <code>fixedThisFn ruft intern fn auf und gibt seinen this-Zeiger ul> an, um ein tieferes Verständnis zu erhalten Um zu erfahren, wie call/apply/bind den Punkt von this in der Funktion ändert, simulieren und implementieren wir diese drei Funktionen separat🎜

    call/ apply/bindQuellcode-Implementierung

    🎜Gemäß der vorherigen Einführung wissen wir: Wenn die Funktion als Objektattribut aufgerufen wird, this Zeigt auf das Objekt das ruft die Funktion auf🎜rrreee🎜Mithilfe der Funktion von JavaScript können wir die ausgeführte Funktion als ersten Parameter context von call/apply > verwenden Attribut und rufen Sie dann die dem Attribut entsprechende Funktion über context auf. Der this der Funktion zeigt auf context🎜🎜call lautet wie folgt: 🎜rrreee🎜An diesem Punkt haben einige Freunde möglicherweise herausgefunden, dass der in <code>call/apply übergebene context kein ist Objekt? 🎜🎜Schauen wir uns zunächst die Beschreibung von mdn des ersten Parameters der Methode call an: 🎜🎜Syntax: function.call(thisArg, arg1, arg2 , ..)
    * thisArg
    Optional. Der this-Wert, der verwendet wird, wenn die Funktion function ausgeführt wird. Beachten Sie, dass this möglicherweise nicht der tatsächliche Wert ist, den die Methode sieht: Wenn sich diese Funktion im nicht-strikten Modus befindet, geben Sie null oder undefiniert an. code> wird automatisch ersetzt, um auf das globale Objekt zu verweisen, und der ursprüngliche Wert wird umschlossen
    🎜🎜Als nächstes verarbeiten wir den ersten Parameter der Methode myOwnCall wie folgt : 🎜 rrreee🎜Rufen Sie diese Funktion in der myOwnCall-Methode auf: 🎜rrreee🎜Die Implementierung von apply ist im Grunde die gleiche wie call, außer dass die Der zweite Parameter ist ein Array: 🎜
    Function.prototype.myOwnBind = function (context, paramsArray) {
      context = translateToObject(context);
      const uniqueKey = new Date().getTime();
      // this为调用call方法的函数
      context[uniqueKey] = this;
      // 作为对象的方法被对象调用,this指向该对象context
      const result = context[uniqueKey](...paramsArray);
      delete context[uniqueKey];
      return result;
    };

    相比于call/applybind函数并没有立即执行函数,而是预先传入函数执行时的this和参数,并且返回一个函数,在返回的函数中执行调用bind函数并将预先传入的this和参数传入

    bind的源码模拟:

    Function.prototype.myOwnBind = function (context, ...outerArgs) {
      const fn = this;
      return function (...innerArgs) {
        return fn.call(context, ...outerArgs, ...innerArgs);
      };
    };

    精简版如下:

    Function.prototype.myOwnBind = (context, ...outerArgs) => (...innerArgs) => this.call(context, ...outerArgs, ...innerArgs);
    这里并没有实现通过new操作符来执行fn.bind(context)的操作,如果想知道其详细的实现过程,可以看我的这篇文章: JS进阶-手写bind

    在深入理解call/apply/bind的实现原理后,我们尝试完成下面的测试:

    function fn1 () {console.log(1);}
    function fn2 () {console.log(2);}
    fn1.call(fn2);
    
    fn1.call.call(fn2);
    
    Function.prototype.call(fn1);
    Function.prototype.call.call(fn1);

    answer:

    1. 1
    2. 2
    3. 什么都不输出
    4. 1

    这里我们根据call的源码来进行推导一下Function.prototype.call.call(fn1),其它的执行过程类似:

    // 1. 首先会将Function.prototype.call作为一个函数来执行它原型上的call方法
    // 所以call方法内部:
    //    this => Function.prototype.call
    //    context => fn1
    // 通过对象的属性来执行方法改变this指向
    //    fn1[uniqueKey] = this(Function.prototype.call)
    //    fn1[uniqueKey]() // 执行 Function.prototype.call方法,但是this是context
    // 2. 在this为fn1的情况下执行Function.prototype.call方法
    // 所以call方法内部:
    //    this => fn1
    //    context => window
    // 通过对象的属性来改变this指向
    //    window[uniqueKey] = fn1
    //    window[uniqueKey]() // 执行fn1(),但是this是window

    更多编程相关知识,请访问:编程入门!!

    Das obige ist der detaillierte Inhalt vonWohin weist JavaScript?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn