【问题标题】:Are there any pitfalls of declaring variables through this keyword?通过这个关键字声明变量有什么陷阱吗?
【发布时间】:2017-05-17 13:49:01
【问题描述】:

我写了一个简单的对象解构函数,它通过将属性分配给范围对象来声明给定范围内的变量

我可以在生产中使用这个函数吗?如果不能,使用这个函数有什么陷阱?

function destructure(obj, scope) {
  scope = scope || this;
  Object.keys(obj).forEach(key => {
    if (scope[key] === undefined) {
      scope[key] = obj[key];
    } else {
      throw new Error(key + ' variable is already declared.');
    }
  });
}

var o = {
  one: 1,
  two: 2,
  three: 3,
  four: 4
};

destructure(o);

console.log(one); // 1
console.log(two); // 2
console.log(three); // 3
console.log(four); // 4

【问题讨论】:

  • 您假设 this 指向全局对象,但情况并非总是如此。例如,在严格模式下,this 并不指向全局对象。
  • 一个“陷阱”通常是当你试图达到A,但没有意识到你最终得到的是Á(非常相似但略有不同)。但也许你真的想做Á 并且完全了解其中的含义。因此,为了向您展示可能存在的陷阱,我们需要知道您真正想要实现的目标。
  • 我想用这个函数作为一个助手来解构一个函数的参数,这个函数是具有许多属性的对象。
  • 您真的要将对象的所有属性添加到全局范围吗?为什么?下面你说你正在使用 Node.js。我认为 Node 的主要好处之一是能够将代码划分为模块。从这个角度来看,向全局范围/对象添加值似乎是倒退了一步。如果您计划将对象的属性添加到调用函数的范围,那么这通常是不可能的。函数/模块范围不受对象支持,也无法将它们称为对象。

标签: javascript node.js ecmascript-6


【解决方案1】:

通过this关键字声明变量有什么坑吗?

是的:它真的不起作用。


对于this 和作用域的工作方式可能存在误解。

关于范围

只有当环境由实际对象支持时,才能通过向对象添加属性来声明变量。这仅适用于两种情况:

  • 全局范围,(部分)由全局对象支持(浏览器中的window
  • with 声明

例子:

// Global scope
window.foo = 42;
console.log(foo);

// with statement
var obj = {};
with (obj) {
  obj.bar = 21;
  console.log(bar);
 }

既然你提到你正在使用 Node,我想强调 function 范围和 module(它们只是 Node atm 中的函数)范围是 没有对象支持,因此没有办法动态声明变量

关于this

this 的值取决于函数的调用方式。它基本上可以引用任何值。

现在,以“正常方式”调用 (n unbound) 函数,即 f(),具有这种任意行为,this 将引用 全局对象,例如window 在浏览器中。当然,作为全局范围,添加的任何变量都可以在其他任何地方访问,但这不一定是一件好事。

因此,虽然您的解决方案可能看起来有效,但实际上只有在您在全局范围内运行代码时才会巧合。


关于严格模式

Strict mode 改变了一些被认为不正确或危险的行为。最重要的是,它改变了this 在普通函数调用 (f()) 中的行为方式。而不是引用全局对象,它只是undefined。因此,如果你的函数是在严格模式下声明的,你的代码实际上会抛出一个错误。

with 语句在严格模式下也是被禁止的。

在 ES2016 中,类和模块等新结构默认情况下是严格的,因此您可以看到这是该语言的发展方向,您不应依赖在严格模式下不起作用的行为。

【讨论】:

    【解决方案2】:

    通过将属性分配给范围对象来声明给定范围内的变量

    不,这不是变量声明的工作方式。此外,JS 唯一可用的“范围对象”——忽略 with 语句——是全局对象(你碰巧在你的概念证明中使用了它),你不想弄乱那个

    我可以在生产中使用这个功能吗?

    绝对不是。


    如果你认同这个想法,你可能会can hack it with eval,但实际上你只是should use real destructuring like everyone else

    var {one, two, three, four} = o;
    

    【讨论】:

      【解决方案3】:

      这是程序化方法:

      this["one"] = 1
      this["two"] = 2 
      this["three"] = 3
      this["four"] = 4
      

      虽然理论上这很好,但您可能会因为依赖this 而遇到麻烦。最好直接指定global,以免遇到.bind()和朋友的麻烦。

      function destructure(obj, scope) {
        scope = scope; // Remove the this
        Object.assign(scope, obj);
      }
      destructure(o, global) // Explicitly declare global scope
      

      至于内存泄漏、性能等(我觉得这个问题更多地涉及),您必须记住,您分配给global 的所有内容都不会被垃圾收集。你真的应该只向global 添加函数,而且只有在你真的必须这样做的时候。

      【讨论】:

      • 我在 Node.js 环境中运行。
      • 对不起,在这种情况下你可以用global代替window
      【解决方案4】:

      为什么不只使用 Object.assign?

      function destructure(obj, scope) {
        scope = scope || this;
        Object.assign(scope, obj);
      }
      

      【讨论】:

      • 这是一个更好的代码实现,但它没有回答他们的要求。
      • 好主意,但它不检查变量是否已经用值声明。
      猜你喜欢
      • 1970-01-01
      • 2011-06-28
      • 1970-01-01
      • 1970-01-01
      • 2011-10-13
      • 1970-01-01
      • 1970-01-01
      • 2021-12-17
      • 1970-01-01
      相关资源
      最近更新 更多