hax.github.com
hax.github.com copied to clipboard
How you interpret this code? -- test of a imaginary JavaScript code
Note, this is NOT a valid code as current JavaScript syntax. So the choices below are not correct or wrong, please just choose what your intuition tell.
注意,下面的代码目前并不是合法的代码。所以后面的选择没有对错之分,请按照你的直觉选择。
var foo = 0;
class Whatever {
var bar;
constructor(v) {
bar = v;
}
test() {
++foo;
++bar;
return `${foo}:${bar}`;
}
}
var x = new Whatever(10);
x.test(); // output 1:11
var y = new Whatever(20);
y.test(); // output 2:21
x.test(); // output?
y.test(); // output?
Please use 👍 or 👎 to vote. Use 👍 to choose what match your intuition, you could also use 👎 to denote you will never interpret the code like that. If you have other answer, please add comment. Thank you.
请用表情符号投票。👍 表示跟你的直觉相符,你也可以用 👎 表示完全不会这么想。如果你觉得有其他结果,可以留言。谢谢。
Choice A: bar
is an instance variable which each instance of Whatever
have a individual bar
value
选择A:bar
是一个实例变量,每个Whatever
的实例都有各自的bar
值
3:12
4:22
Choice B: bar
is a bit like foo
which shared by all the instances
选择B:bar
跟foo
差不多,所有实例访问的是同一个
3:22
4:23
I think B is better.it's confirm to the js's grammer
For choice B, is it drop support for instance variable? or just not shown in the code? 选项 B 是不支持创建实例变量吗?还是只是目前的代码里没有示例?
@amio Just not demo-ed IMO 应该只是没有示例
@SmallGress This is not which is better question. Don't think too much about it. Just use your intuition. 这不是一个“哪一个更好”的问题。不要想得太多,直接按你的第一直觉来就好了。
@amio
This is not a poll for which is the better syntax of instance variable. In fact I don't think poll is a good way to choose syntax of new feature because it's too complex for most programmers to see all consequences of a syntax. But we can use a poll to test a much simple, much specific issue. So this is just a test to see whether programmers would be confused if we use var
to declare instance var in the class.
It will not ambiguous if we write: 写成这样就没歧义了吧:
var foo = 0;
class Whatever {
var bar; // private instance field, use 'this->bar' for reference
constructor(v) {
this->bar = v;
}
test() {
++foo;
this->bar++;
return `${foo}:${this->bar}`;
}
}
@zheeeng
It's may much clear bar
is instance var if we using class1.1 full syntax this->bar
to differentiate foo
, but it also throw another question, how programmers see var bar
in the class as a declaration for this->bar
. Anyway, this poll is try to investigate the intuitions of the shortcut form. Because if class1.1 proposal support bar
as a shortcut form of this->bar
, then I guess programmers will mostly use bar
in the code, only use this->bar
or other->bar
in rare case.
使用class1.1提案的 this->bar
语法以区分 foo
当然会让大家更清楚 bar
实际上是实例变量,不过有另外一个问题,程序员是否第一眼就认为class里的var bar
会对应this->bar
呢?但这些不是本测试的目的,本测试是为了看看直接写成bar
的这个方式是否符合大家的直觉。因为如果class1.1提案支持把this->bar
简写为bar
,那么估计我们大部分时候在代码里都是直接写bar
,只有少数时候会使用this->bar
(函数里有bar
同名变量)或other->bar
(other
是外面传进来的另一个实例)。
My intuition tells me that just treat Class
as a function and then translate the code like:
var foo = 0;
function Whatever(v) {
var bar;
bar = v;
return {
test: function () {
++foo;
++bar;
return foo + ":" + bar;
}
}
}
var x = new Whatever(10);
x.test(); // 1:11
var y = new Whatever(20);
y.test(); // 2:21
x.test(); // 3:12
y.test(); // 4:22
Of course, they are not equivalent. The point I want to express is that my intuition treated bar
as a local variable, rather than an instance variable. x.test
and y.test
are both closures, they share the same function body definition but store different lexical environments.
That's why I choose A.
@hax 切记class只是语法糖啊!Choice A是搞哪一出?
截至ES2018,Whatever.prototype.a=function(){}
能写成class形式(像这样:class Whatever{a(){}}
),Whatever.prototype.b=1
却写不成class形式。想问这种不一致是有意的吗?
Keep in mind that class is just syntactic sugar! What is Choice A doing?
In ES2018, Whatever.prototype.a=function(){}
can be rewriten in class-style like class Whatever{a(){}}
while Whatever.prototype.b=1
cannot. Tell whether the inconsistency is deliberate.
For Choice A, consider:
Whatever.prototype.test.call(x); // ????
y.test.call(x); // ????
Whatever.prototype.test.call(class{var bar = 0}); // ????
Whatever.prototype.test.call(class{}); // ????
Whatever.prototype.test.call(class{var foo = 0}); // ????
(function(){return foo}).call(class{var foo = 0}); // ????
(() => foo).call(class{var foo = 0}); // ????
@dou4cc
这个测试只是用来看看大家对 class
级别的 var
直觉上的反应。不用想得太深。
当然,如果你对这种用法感到很抵触,可以通过投票表示。
This is only a test to investigate the intuition of the programmers if they see class
-level var
usage. Don't think too much. But you of coz can vote against it if you think it's a "wrong" thing.
我个人建议不要把class
当做语法糖来看待,而是把prototype看成是class的内部细节。当然基于prototype必然对ES6+ class的设计产生影响,你说的只有“方法”没有“属性/数据字段”就是后果之一。这里有个有趣的事情是,如果一定要说语法糖的话,你觉得class-level的var应该是每实例上还是原型上的属性呢?还是其他?
I will recommend that don't treat class
as syntactic sugar, but treat prototype as the inner details of class. Of coz, the fact that ES6+ class is based on prototype cause consequence to the design, one of it is only "methods" but no "properties/data fields". I doubt how you think class-level var in the view of syntactic sugar? Property per-instance, or property on the prototype? or other?
至于后面你写的那些例子,这体现了你在考虑this
动态绑定的语义问题。当然这是一个重要的问题,提案必须要给出精确的语义。但是这不代表这对于实际代码一定是特别重要的问题。可以做某件事(比如把 class 上的方法扒下来绑一个其他 context 调用),不代表你真的有需求在代码里这么用。我希望咱们能聊一些更为切实的 use case,看看会有什么问题。谢谢。
About the code examples of call
usage, I believe you are considering the semantic of this
binding. It's a important issue for the spec, the proposal should give precise semantic for every possible usage. But I don't think it's a important issue for real coding. We have the ability to do something (like extract the method from a instance of a class and call it with other context), don't necessarily mean you have a real use case in the daily coding. I hope we can focus on some much real use cases, and figure out if there is any problem. Thank you.
@hax
我个人建议不要把
class
当做语法糖来看待,而是把prototype看成是class的内部细节。当然基于prototype必然对ES6+ class的设计产生影响,你说的只有“方法”没有“属性/数据字段”就是后果之一。这里有个有趣的事情是,如果一定要说语法糖的话,你觉得class-level的var应该是每实例上还是原型上的属性呢?还是其他?
I choosed B.
In ES2018, Whatever.prototype.a=function(){}
can be rewriten in class-style like class Whatever{a(){}}
while Whatever.prototype.b=1
cannot. Tell whether the inconsistency is deliberate.
至于后面你写的那些例子,这体现了你在考虑
this
动态绑定的语义问题。当然这是一个重要的问题,提案必须要给出精确的语义。但是这不代表这对于实际代码一定是特别重要的问题。可以做某件事(比如把 class 上的方法扒下来绑一个其他 context 调用),不代表你真的有需求在代码里这么用。我希望咱们能聊一些更为切实的 use case,看看会有什么问题。谢谢。
You are against not only prototype but also implementation of existing native methods.
Carefully review the following usual code:
[].map.call(["1", "2", "3"], a => +a); // [1, 2, 3]
[].map.call("123", a => +a); // [1, 2, 3]
[].map.call(null, a => +a); // TypeError
When binding context is needed, https://github.com/hax/hax.github.com/issues/44#issuecomment-374545055 is just ok. To support switching to different context, what we need is not syntax.
@dou4cc 我不是很明白你的意思。你能不能先明确的说一下你直觉上class-level的var应该是每实例上还是原型上的属性呢?还是其他?
You are against not only prototype but also implementation of existing native methods.
完全不明白你在说什么。也许你用中文直接写会比较容易点?
我再解释一次,这个测试的目的只是为了看大家对于这个代码的直觉。当然我们可以在某项前提下讨论具体的语义(比如call)。
@hax I choosed B.
@dou4cc 我知道你选B。我不清楚的是你的其他意思。实例变量跟原型没有关系。
@hax 具体而言我希望var是原型上的属性。我一直好奇你们为什么不提供这样的class风格的写法。
@hax 更准确地说,我希望的是let和const,我不希望再有var了。let和const对应可写和只读。
@dou4cc 我大概理解了,你是希望有语法针对原型上的属性?但是原型属性存在一些问题。所以ES6 class就没有加。你可以看我去年演讲的 slide :http://johnhax.net/2017/js-private/slide?qcon#43 。所以不管哪一份草案都不支持原型属性。
至于 let / const ,只是关键字的差别,跟原型没有关系。如果你关心为什么这份草案使用了 var 而不是 let/const,可以看 class1.1 里的 25 号 issue(我不贴链接了,避免产生引用)。
我一直好奇你们为什么不提供这样的class风格的写法。
@dou4cc 我并不是TC39的成员。所以这个问题我不能做最权威的回答。不过基本原因就是我前面说的。
另外,我们每个人当然都有自由去相关proposal的讨论里发表意见。我觉得中国程序员去参与标准讨论是一件好事。不过标准提案的讨论的门槛是有点高的,而且又有英语的门槛。如果中国人都弄不懂你的意思,估计老外也看不懂。所以如果对一些问题不是特别清楚,欢迎先在这里提问,我会尽力解释。谢谢。
另外为了保护隐私起见,我把之前你留的联系方式删除了哦。
作为一个 Jser,以前从未见过那样的语法,所以选 A 或选 B 都可能是对的 As a Jser, I have never seen such a grammar before, so choosing either A or B may be right
作为一个 Javaer,我们习惯于这么定义成员变量 As a Javaer, we are used to defining member variables like this
class Whatever {
private int bar = 1;
}
如果去掉权限修饰符 (private) 和默认值
If we remove access modifiers (private
) and default values
class Whatever {
int bar;
}
再使用 var
代替 int
And use var
instead of int
class Whatever {
var bar;
}
就跟上面一模一样了,所以我选 A Just like the above, so I choose A
If
class foo {
bar = 0;
}
means per-instance, then this should mean per-instance.
However, personally, I do think this is against javascript semantics. If class has a scope, then the declaration should be of the class scope, which means, "static", for both.
However, class does not mean a scope. How can you declare a variable without linking it to a scope ? That is wired, and "magic".
Besides, how should it work by your design, and how can this make the variables private ?
@yw662
This investigation is try to find what most javascript programmer's intuition on x
is when they see class { var x }
without any teaching. The vote result "145:21" has proved that most js programmers see x
is per instance.
then the declaration should be of the class scope, which means, "static", for both.
On the other side, because most js programmers already know static
so if they need a var which shared by all instances, they will just use static
or outer var
. If inner var
just do the same thing, then the syntax is just useless. So they will think if this is a meaningful syntax, then it should mean per-instance.
how should it work by your design, and how can this make the variables private ?
The interesting part is, we do not need any magic like "this.#x" to make it "private". When you see
function C(v) {
var x = v
this.getX = function () { return x }
}
const c1 = new C(1)
const c2 = new C(2)
Would you think there is any way you can access x
value for c1/c2
instances except calling getX()
?
Actually, js programmers know there is no way to access it because x
is the local var of the constructor.
The same intuition could apply to:
class C {
var x
constructor(v) { x = v }
getX() { return x }
}
const c1 = new C(1)
const c2 = new C(2)
So you just know there is no way to access x
of c1/c2
except calling c1.getX()
or c2.getX()
.
@yw662
The classes 1.1 proposal is an alternative proposal for current field proposal. Even you think this proposal is not attractive, you should compare it to current this.#x
proposal. If you must have to choose one, which one is better? Some members of TC39 just want to push this.#x
to the standard, and some part of it already enabled in the Chrome canary! They can push it because they tell everyone there is no other better proposal.
I know you may don't want either. But unfortunately it already been you should choose the one you dislike the less. And recently, they just decide to refuse all alternatives. So that means you have no choice but just accept this.#x
. I hope you already know the situation, and if you really don't want this.#x
, you should tell TC39 that you think classes 1.1 is a better proposal so please do not use "there is no other alternative" as the excuse to push this.#x
.
The private
here means, private but can be accessed by all members, which is semantically different from closure
. If your implementation means no more than closure, it is not same with foo.#bar
.
As a result, you do need magic to achieve this. You must allow foo.bar
in member functions when bar
is private
, and deny it if foo.bar
accessed outside of the class.
I personally love the closure implementation for private variables, and do think introducing a new private mechanism will definitely mess up the semantics. Actually I personally dislike all of the class
things indeed. These are just hacks to semantics.
However,
foo.#bar
feels like bad code, but is less magic.
Your proposal seems not so bad, but is not javascript.
So I would rather choose foo.#bar
.