在顶层调用node.js对象的“范围”是什么? [英] What scope is 'this' of a node.js object when it gets called at the top-level?

查看:55
本文介绍了在顶层调用node.js对象的“范围”是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我阅读了为什么以及如何在React组件类中绑定方法? 并掌握了 this 与所调用的作用域有何不同的基本思想。



我做了一个简单的类来对此进行测试。

  class {
构造函数(some){
this.some = some;
}

print(){
console.log(
print from,
this,
this === undefined? !!这是未定义的!!:this.some
);
}
}

据我了解,<$ c的范围$ c>此可以不同,尽管它来自同一对象(实例)。

  const一些=新的Something(是); 
some.print(); //定义为 this。 this.some是 is。

const go = some.print;
going(); //‘this’未定义。
go.call(some); //定义为 this。 this.some是 is。

但是,为什么 this (其中应该是对象本身)在后一种情况下 undefined ?它不是顶级 this ,它是一个空对象 {} 吗?

解决方案

有一个函数 print



当您这样称呼时

  some.print(); 

有效地转换为此值的

  print.call(some,... args)

何时您只需将其拔出

  const前进= some.print 

您刚刚获得了对独立功能的引用,因此可以用

 <$ c来调用它$ c> going()

与致电


$ b相同$ b

  print(); 

它是在<$ c $之间c> some 和 print 神奇地传递了 some 作为打印 going()没有句号,因此不予传递。



请注意,您可以分配要转到的对象和使用句点运算符进行魔术操作将左侧的内容作为 this 传递



  function print(){console.log(this);} const someObj = {foo:print,}; someObj.foo();  



所有 class 关键字确实有助于将打印内容分配给事物的原型

 类Something { 
print(){console.log(this); }
}


$ b $相同b

  function Something(){} //构造函数
Something.prototype.print = function(){console.log(this});

实际上也与此相同

  function print(){console.log(this); } 
function Something(){} //构造函数
Something.prototype.print = print;

Saikat使用 bind 显示。有效地绑定将产生一个新功能,该新功能包装了您的旧功能。示例

  const会= print.bind(foo); 

几乎与



<$ p $相同p> function createAFuncitonThatPassesAFixedThis(fn,objectToUseAsThis){
return function(... args){
return fn.call(objectToUseAsThis,... args);
}
}

const前往= createAFunctionThatPassesAFixedThis(print,foo);
going(); //用'foo'调用print,因为

某些其他答案似乎具有基本意义对 this 的误解。 不是所有者,也不是当前对象的 this this 实际上只是函数内的另一个变量。如果在函数调用中使用运算符,它将自动设置。因此 a b()设置 a 。如果不存在点运算符,您仍然可以通过使用 call apply <来设置 this / code>如 somefuntion.call(valueForThis,... args) somefunction.apply(valueForThis,[... args ]);



  function print(){ console.log(this.name);} print.call({name: test}); //打印testconst foo = {name: foo,bar:print,}; foo.bar(); //打印foofunction Something(name){this.name = name;} Something.prototype.someFunc = print; const s = new Something( something); s.someFunc(); //打印出一些东西。foobar = print; s.foobar(); //打印内容 



还要注意ES6添加了 => 箭头运算符,它将 this 绑定到创建函数时的状态。换句话说,

  const foo =()=> {console.log(this); } 



<$ p $相同p> const foo = function(){console.log(this); } .bind(this);

还应该清楚,两个由 bind 和箭头功能,您无法使用调用 apply this c $ c>,因为实际上他们制作了一个包装器,始终将 this 设置为制作包装器时的状态,就像 createAFuncitonThatPassesAFixedThis 在上面做了。



让我们添加一些注释以显示我的意思

  function createAFuncitonThatPassesAFixedThis(fn,objectToUseAsThis){

//返回使用objectToUsAsThis调用fn的函数,例如
返回函数(... args){

//当我们从
下面的 going.call行到达此处时,`this`将是 someObject
// //但在下一行中,我们将 objectToUseAsThis传递给fn as
//因此, someObject实际上被忽略了。

return fn.call(objectToUseAsThis,... args);
}
}

const前往= createAFunctionThatPassesAFixedThis(print,foo);
going.call(someObject); //将某些对象作为 this传递

还有一件事情。通常使用 bind 为事件侦听器或回调函数。这在React中很常见示例

 类组件扩展了React.Component {
构造函数(props){
超级属性(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
//这将是当前组件,因为我们将 this绑定在
上方console.log( clicked);
}
render(){
return(< button onClick = {this.handleClick}> click me< / button>);
}
}

这至少可以通过3种常见方式进行处理。


  1. 在构造函数中使用 bind (见上文)


  2. 在渲染中使用 bind

      render(){
    return(< button onClick = {this.handleClick.bind(this)}> click me< / button>);
    }


  3. 在渲染中使用箭头功能

      render(){
    return(< button onClick = {()=> {this.handleClick();}}>点击我< ; / button>);
    }


上面我显示了什么 bind => 实际上与 createAFuncitonThatPassesAFixedThis 一起使用。他们创建了一个新功能。因此应该清楚地说明,如果每次调用 render 时都使用上述样式2或3,则会创建一个新函数。如果使用样式1,则仅在构造函数中创建一个新函数。这是否重要很重要。创建更多功能意味着更多垃圾,这意味着网页可能会变慢,但在大多数情况下,除非您拥有不断渲染的疯狂复杂网页,否则这三种方式中的哪一种都不重要。


I read "Why and how to bind methods in your React component classes?" and grabbed the basic idea of how different is this by the scopes it gets called.

I made a simple class to test this.

class Something {
  constructor(some) {
    this.some = some;
  }

  print() {
    console.log(
      "print from ",
      this,
      this === undefined ? "!!this is undefined!!" : this.some
    );
  }
}

From what I understood, the scope of this can be different although it is from the same object (instance).

const some = new Something("is");
some.print(); // 'this' is defined. 'this.some' is 'is'.

const going = some.print;
going(); // 'this' is undefined.
going.call(some); // 'this' is defined. 'this.some' is 'is'.

But then, why is this (which should be the object itself) undefined in the latter case? Shouldn't it be the top-level this, which is an empty object {}?

解决方案

there's a function print

when you call it like this

some.print();

that effectively gets translated to this

print.call(some, ...args)

When you just pull it out

const going = some.print

You've just gotten a reference to the standalone function so calling it with

going()

Is the same as calling

print();

It's the . between some and print that is magically passing some as this to print. going() has no period so no this is passed.

Note that you could assign going to an object and use the period operator to do the magic "pass the thing on the left as this" operation

function print() {
  console.log(this);
}

const someObj = {
  foo: print,
};

someObj.foo();

all the class keyword does is help assign print to Something's prototype

class Something {
  print() { console.log(this); }
}

is the same as

function Something() {}  // the constructor
Something.prototype.print = function() { console.log(this} );

which is also effectively the same as this

function print() { console.log(this); }
function Something() {}  // the constructor
Something.prototype.print = print;

Saikat showed using bind. Bind effectively makes a new function that wraps your old function. Example

const going = print.bind(foo);

Is nearly the same as

function createAFuncitonThatPassesAFixedThis(fn, objectToUseAsThis) {
  return function(...args) {
    return fn.call(objectToUseAsThis, ...args);
  }
}

const going = createAFunctionThatPassesAFixedThis(print, foo);
going();  // calls print with 'foo' as this

Some of the other answers have appear to have a fundamental mis-understanding of this. this is not the "owner" nor is this the current object. this is just effectively another variable inside a function. It gets set automatically if you use the . operator with a function call. so a . b() sets this to a. if the dot operator did not exist you could still set this by using call or apply as in somefuntion.call(valueForThis, ...args) or somefunction.apply(valueForThis, [...args]);

function print() {
  console.log(this.name);
}

print.call({name: "test"});  // prints test

const foo = {
  name: "foo",
  bar: print,
};

foo.bar();  // prints foo

function Something(name) {
  this.name = name;
}
Something.prototype.someFunc = print;

const s = new Something("something");
s.someFunc();  // prints something

s.foobar = print;
s.foobar();   // prints something

Also note that ES6 added the => arrow operator which binds this to whatever it was when the function is created. In other words

const foo = () => { console.log(this); }

Is the same as

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

it should also be clear that both functions made with bind and arrow functions you can not change this using call or apply since effectively they made a wrapper that always sets this to what it was when the wrapper was made just like createAFuncitonThatPassesAFixedThis did above.

Let's add some comments to show what I mean

function createAFuncitonThatPassesAFixedThis(fn, objectToUseAsThis) {

  // return a function that calls fn with objectToUsAsThis as this
  return function(...args) {

    // when we arrive here from the "going.call" line below
    // `this` will be "someObject"
    // but on the next line we're passing "objectToUseAsThis" to fn as this
    // so "someObject" is effectively ignored.

    return fn.call(objectToUseAsThis, ...args);
  }
}

const going = createAFunctionThatPassesAFixedThis(print, foo);
going.call(someObject);  // pass some object as `this`

One more thing. It's very common to use bind to make a function for an event listener or callback. It's very common in React. Example

class Component extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    // 'this' will be the current component since we bound 'this' above
    console.log("was clicked");
  }
  render() {
    return (<button onClick={this.handleClick}>click me</button>);
  }
}

This would be handled in at least 3 common ways.

  1. Using bind in the constructor (see above)

  2. Using bind in render

      render() {
        return (<button onClick={this.handleClick.bind(this)}>click me</button>);
      }
    

  3. Using arrow functions in render

      render() {
        return (<button onClick={() => { this.handleClick(); }}>click me</button>);
      }
    

Above I showed what bind and => actually do with createAFuncitonThatPassesAFixedThis. They create a new function. So that should make it clear that if use style 2 or 3 above when every single time render is called a new function is created. If you use style 1 then a new function is only created in the constructor. It's a style issue as to whether or not that's important. Creating more functions means more garbage which means a possibly slower webpage but in most cases unless you have a crazy complicated webpage that is rendering constantly it probably doesn't matter which of the 3 ways you do it.

这篇关于在顶层调用node.js对象的“范围”是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆