关于前端:一个能够确定-this-值的算法

38次阅读

共计 4573 个字符,预计需要花费 12 分钟才能阅读完成。

每个 JavaScript 程序猿,包含我本人,都始终在致力理解 this 关键字在代码中的真正身份。

我设计了一个通用算法,能够帮你在任何状况下确定 this 关键字的值。尽管我尽可能的使算法容易看懂,但还是倡议你多看几遍并了解相干术语。

另外还用了几个例子展现怎么用这个算法一步一步的对 this 进行评估,最初你本人亲自试一试。

1. this 算法

把算法定义为 ThisValueOfFunction(func, invocationType),返回值为在以 invocationtype 形式调用函数 func 时的 this 值:

ThisValueOfFunction(func, invocationType):

  1. 如果 func 是一个 箭头函数,那么

    1. 如果 func 是在 最里面的作用域 中定义的,那么返回 globalObject
    2. 否则

      1. SuffeFuncFunc 内部函数
      2. 返回 ThisValueOfFunction(outerFunc, outerInvocationType)
  2. 如果 funcoriginFunc 函数的 绑定函数,那么

    1. thisArgFunc = OriginFunc.bind(thisarg) 的参数
    2. 返回 thisArg
  3. 如果 funcsomeclass 中的 constructor() 办法,那么

    1. instanceinstance = new SomeClass() 的实例
    2. 返回 instance
  4. 如果 func 是一个 惯例函数,那么

    1. 如果 invocationtype 作为构造函数,那么

      1. newObject 是新结构的对象 newObject = new func()
      2. 返回 newObject
    2. 如果 invocationtype 是间接调用 的,那么

      1. thisArgfunc.call(thisArg)func.apply(thisArg) 的参数
      2. 返回 thisArg
    3. 如果 invocationtype办法,那么

      1. object 是在 object.func() 上调用 func 的对象
      2. 返回 object
    4. 如果 invocationtype 惯例的,那么

      1. 如果启用了 严格的模式,那么返回 undefined
      2. 否则返回 globalObject

1.1 算法中应用的术语

这个算法应用了大量的 JavaScript 术语。如果你不相熟某些货色,先看上面的解释。

  • 箭头函数

    箭头函数是应用粗箭头语法 => 定义的函数。箭头函数示例:

    const sum = (number1, number2) => {return number1 + number2;}
  • 绑定函数

    绑定函数是通过在函数上调用办法 myFunc.bind(thisArg, arg1, ..., argN)创立的函数。绑定函数的示例:

    function originalFunction() {// ...}
    
    const boundFunction = originalFunction.bind({prop: 'Value'});
  • 惯例函数

    惯例函数是用 function 关键字或在对象上定义的简略 JavaScript 函数。惯例函数的示例:

    function regularFunction(who) {return `Hello, ${who}!`;
    }
    
    const object = {anotherRegularFunction(who) {return `Good bye, ${who}!`
      }
    };
  • constructor()

    constructor()class 外部的一种非凡办法,用于初始化类实例。

    class SomeClass() {constructor(prop) {this.prop = prop;}
    }
  • 最内部的作用域

    最内部的作用域是没有内部作用域的最顶级作用域。

    // 最内部的作用域
    let a = 1;
    
    function someFunction() {// someFunction() 的作用域
      // 这里不是最内部的作用域
      let b = 1;
    }
  • 内部函数
    内部函数在其作用域内蕴含另一个函数。

    // outerFunction() 是 myFunction() 的内部函数
    function outerFunction() {function myFunction() {//...}
    }
  • 全局对象

    全局对象是在全局作用域内始终存在的对象。window 是浏览器环境中的全局对象,在 Node 环境中是 global

  • 调用
    函数的调用只是应用一些参数来调用该函数。

    function sum(number1, number2) {return number1 + number2;}
    sum(1, 3);           // 调用
    sum.call({}, 3, 4);  // 调用
    sum.apply({}, 5, 9); // 调用
    
    const obj = {method() {return 'Some method';}
    };
    obj.method(); // 调用
    
    class SomeClass {constructor(prop) {this.prop = prop;} 
    }
    const instance = new SomeClass('Value'); // 调用
  • 结构函数调用
    应用 new 关键字调用函数或类时,将产生结构函数调用。

    function MyCat(name) {this.name = name;}
    const fluffy = new MyCat('Fluffy'); // 结构函数调用
    
    class MyDog {constructor(name) {this.name = name;}
    }
    const rex = new MyDog('Rex'); // 结构函数调用
  • 间接调用
    应用 func.call(thisArg, ...)func.apply(thisArg, ...) 办法调用函数时,会产生间接调用。

    function sum(number1, number2) {return number1 + number2;}
    
    sum.call({}, 1, 2);  // 间接调用
    sum.apply({}, 3, 5); // 间接调用
  • 办法调用
    当在属性拜访器表达式 object.method() 中调用函数时,将产生办法调用。

    const object = {greeting(who) {return `Hello, ${who}!`
      }
    };
    
    object.greeting('World');    // 办法调用
    object['greeting']('World'); // 办法调用
  • 惯例调用
    只用函数参数变量调用 func(...) 时,会产生惯例调用。

    function sum(number1, number2) {return number1 + number2;}
    
    sum(1, 4); // 惯例调用
  • 严格模式
    严格模式是对运行 JavaScript 代码有非凡限度的一种非凡模式。通过在脚本的结尾或函数作用域的顶部增加 use strict 指令来启用严格模式。

2. 例子

例 1

const myFunc = () => {console.log(this); // logs `window`};

myFunc();

ThisValueOfFunction(myFunc,“惯例的”)

myfunc 是箭头函数:从而在算法中匹配状况 1。同时 myFunc 在最里面的作用域内定义,匹配状况 1.1

算法 1.1 中返回 globalObject 意思是 myFunc 中的 this 值为全局对象 window(在浏览器环境中)。

例 2

const object = {method() {console.log(this); // logs {method() {...} }  } 
};

object.method();

ThisValueOfFunction(object.method,“作为办法调用”)

method() 同时是 object 的属性,是惯例函数。与算法的状况 4 匹配。

object.method() 是一种办法调用,因为是属性拜访的,送一因而与 4.3 匹配。

而后,依据 4.3method() 办法中的 this 等于办法的拥有者 (object.method()) — object

例 3

function MyCat(name) {
  this.name = name;

  const getName = () => {console.log(this); // logs {name: 'Fluffy', getName() {...} }    return this.name;
  }

  this.getName = getName;
}

const fluffy = new MyCat('Fluffy');
fluffy.getName();

ThisValueOfFunction(getName,“作为办法调用”)

getName() 是一个箭头函数,所以合乎算法的状况 1;因为 mycatgetName()的内部函数,而后与 1.2 匹配。

分支 1.2.2thisgetName() 箭头函数外部的值等于内部函数的值 MyCat

所以让咱们在 MyCat 函数上运行算法 ThisValueOfFunction(MyCat, "做为构造函数")

ThisValueOfFunction(MyCat,“作为构造函数”)

MyCat 是惯例函数,所以跳转到算法的分支 4

因为 MyCat 做为结构函数调用 new MyCat('Fluffy'),合乎分支 4.1。最初依据 4.1.14.1.2thisMyCat 中等于结构的对象:fluffy

而后,返回箭头函数后合乎 1.2.2,在 getname() 中的 this 等于 mycatthis,最终后果为 fluffy

3. 练习

要了解这个算法,最好本人亲自试试。上面是 3 个练习。

练习 1

const myRegularFunc = function() {console.log(this); // logs ???};

myRegularFunc();

如何确定 myRegularFunc() 中的 this 值?写出你的判断步骤。

练习 2

class MyCat {constructor(name) {
    this.name = name;
    console.log(this); // logs ???  }
}

const myCat = new MyCat('Lucy');

如何确定 new MyCat('Lucy') 中的 this 值?写出你的判断步骤。

练习 3

const object = {
  name: 'Batman',

  getName() {const arrow = () => {console.log(this); // logs ???      return this.name;
    };

    return arrow();};
}

object.getName();

如何确定 arrow() 中的 this 值?写出你的判断步骤。


本文首发微信公众号:前端先锋

欢送扫描二维码关注公众号,每天都给你推送陈腐的前端技术文章


欢送持续浏览本专栏其它高赞文章:

  • 深刻了解 Shadow DOM v1
  • 一步步教你用 WebVR 实现虚拟现实游戏
  • 13 个帮你进步开发效率的古代 CSS 框架
  • 疾速上手 BootstrapVue
  • JavaScript 引擎是如何工作的?从调用栈到 Promise 你须要晓得的所有
  • WebSocket 实战:在 Node 和 React 之间进行实时通信
  • 对于 Git 的 20 个面试题
  • 深刻解析 Node.js 的 console.log
  • Node.js 到底是什么?
  • 30 分钟用 Node.js 构建一个 API 服务器
  • Javascript 的对象拷贝
  • 程序员 30 岁前月薪达不到 30K,该何去何从
  • 14 个最好的 JavaScript 数据可视化库
  • 8 个给前端的顶级 VS Code 扩大插件
  • Node.js 多线程齐全指南
  • 把 HTML 转成 PDF 的 4 个计划及实现

  • 更多文章 …

正文完
 0