在顶层调用node.js对象的“范围”是什么? [英] What scope is 'this' of a node.js object when it gets called at the top-level?
问题描述
我阅读了为什么以及如何在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 $ c进行的函数$ c>和箭头功能,您无法使用
调用
或 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种常见方式进行处理。
-
在构造函数中使用
bind
(见上文) -
在渲染中使用
bind
render(){
return(< button onClick = {this.handleClick.bind(this)}> click me< / button>);
}
-
在渲染中使用箭头功能
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.
Using
bind
in the constructor (see above)Using
bind
in renderrender() { return (<button onClick={this.handleClick.bind(this)}>click me</button>); }
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屋!