您对使用JavaScript打高尔夫球有哪些一般提示?我正在寻找可以应用于编码高尔夫问题的想法,这些想法至少在某种程度上特定于JavaScript(例如,“删除评论”不是答案)。
注意:另请参阅ECMAScript 6及更高版本中的打高尔夫球技巧
您对使用JavaScript打高尔夫球有哪些一般提示?我正在寻找可以应用于编码高尔夫问题的想法,这些想法至少在某种程度上特定于JavaScript(例如,“删除评论”不是答案)。
注意:另请参阅ECMAScript 6及更高版本中的打高尔夫球技巧
Answers:
您可以通过非标准方式将标准用于循环
for ( a; b; c )
本质上等同于:
a;
while ( b )
{
...
c;
}
所以一个好的技巧是一个编写代码while
回路,然后将其拆分成a,b,c
一个部件for
循环。
我写了几个例子:
for(x=y=n;!z;x--,y++)z=i(x)?x:i(y)?y:0
for(a=b=1;b<n;c=a+b,a=b,b=c);
如果要初始化或重置多个值,请将值链接到需要它的所有变量:
a=b=1;
不要检查您的类型,只需按原样使用它们即可。parseInt()
花费10
字符。如果您需要排除字符串,请发挥创意:
a='30';
b='10';
c = a + b; //failure
c = parseInt(a) + parseInt(b) //too long
c = -(-a-b); //try these
c = ~~a+~~b;
c = +a+ +b;
c = a- -b;
JavaScript具有自动分号插入功能。经常使用它。
通过将尽可能多的单行或参数推入括号来节省费用:
a( realParam1, realParam2, fizz='buzz' )
a = a - 1;
foo(a);
和
foo(a);
a = a - 1;
可以很容易地重写为
foo(--a);
和
foo(a--);
分别。
this
或self
代替window
自我解释2个字符的节省。
这绝对是属性名称长度和访问次数之间的一种平衡行为。a.longFunctionName()
与使用两次点号调用相比,保存名称并通过方括号调用该函数要短一些:
a.longFunctionName(b)
a.longFunctionName(c)
//42
-vs-
a[f='longFunctionName'](b)
a[f](c)
//34
这document.getElementById
对于可以减少到的功能尤其有效d[e]
。
注意:
使用方括号符号时,成本是6 + name.length
第一次字符。每个后续访问都有一个3
字符成本。
对于点表示法,所有访问都使用name.length + 1
(.
字符为+1 )。
如果使用此方法6 + name.length + (3 * (accesses - 1)) < accesses * (name.length + 1)
。
len =属性名称的长度
i =可以利用的最少访问权限
len | i
========
1 | ∞
2 | ∞
3 | 7
4 | 4
5 | 3
6 | 3
7 | 3
8+ | 2
访问次数也可以跨越多个对象。如果您.length
在不同的数组上访问4次或更多次,则可以使用包含string的相同变量'length'
。
c = ~~a-~~b
应该是c = ~~a+~~b
。另外,您可以使用隐式转换为整数|0
,例如Math.random()*6|0
。
a
和b
是字符串,则可以+a+b
转换为数字并添加它们。
d- -b
有一天要在我的代码中使用...
a.f=a.longfunctionname;a.f(b);a.f(c);a.f(d)
"alpha,bravo,charlie".split(",") // before
"alpha0bravo0charlie".split(0) // after
.split`...`
"alpha,bravo,charlie".split`,`
如果您需要一个随机布尔值(0
或1
):
new Date&1 // equivalent to Math.random()<0.5
如果您需要一个随机整数0 <= n < 1337
:
new Date%1337 // equivalent to Math.floor(Math.random()*1337))
之所以Date
可行,是因为a 从一个纪元以来以毫秒为单位存储在JavaScript中,因此当您尝试对其进行整数数学运算时,它new Date
被强制转换为123somebignumber456
。
当然,这些“随机”数实际上不会是随机的,尤其是如果您连续快速多次调用它们时,请记住这一点。
您可以使用get / set的对象文字形式来避免使用关键字function
。
var obj = {
get f(){
console.log("just accessing this variable runs this code");
return "this is actually a function";
},
set f(v){
console.log("you can do whatever you want in here, passed: " + v);
}
};
1 && obj.f; // runs obj.[[get f]]
obj.f = Infinity; // runs obj.[[set f]](Infinity)
这一名称鲜为人知,使用较少,但如果在正确的情况下使用,会给人留下深刻的印象。考虑一个不带参数的函数,该函数在调用时总是返回一个不同的数字,并且返回的数字将用于计算:
var a = [
Math.random()*12|0,
Math.random()*11|0,
Math.random()*10|0,
/* etc... */
];
您通常可以使用单字母变量名称来缩短此功能:
var r=Math.random,a=[r()*12|0,r()*11|0,r()*10|0,r()*9|0,r()*8|0,r()*7|0,r()*6|0,r()*5|0];
减少长度的更好方法是滥用valueOf
,每次调用可以节省2个字符。如果多次调用该函数很有用:
var r={valueOf:Math.random},a=[r*12|0,r*11|0,r*10|0,r*9|0r*8|0,r*7|0,r*6|0,r*5|0];
let a=[5,6,7,8,9,10,11,12].map(x=>x*Math.random()|0)
或let a=Array(7).map((_,i)=>i*Math.random()|0+5)
,分别保存36或42个字节。
r()
或使其更短?
r={valueOf:Math.random}
那只是天才:D
无需if
使用长语句或使用三元运算符,而是可以使用&&
和||
缩短代码。例如:
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : null;
可以变成
var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
该||
运营商经常使用这种方式设置默认值:
evt = evt || window.event;
这和写作一样
if (!evt)
evt = window.event;
如果要初始化一个特定字符的长字符串,可以通过创建一个长度为n + 1的数组来实现,其中n是您希望重复该字符的次数:
// Create a string with 30 spaces
str = " ";
// or
str = Array(31).join(" ");
字符串越大,节省的费用就越大。
使用+
and ~
运算符代替parseFloat()
或parseInt()
在将只是数字的字符串类型合并为数字类型时:
var num = "12.6";
parseFloat(num) === +num; // + is 10 characters shorter than parseFloat()
var num2 = "12"
parseInt(num2) === +num2; // + is 8 characters shorter than parseInt()
var num3 = "12.6"
parseInt(num3) === ~~num3; // ~~ is 7 characters shorter than parseInt()
var num4 = "12.6"
parseInt(num4) === num4|0; // |0 is 7 characters shorter than parseInt()
不过请注意,其他类型可以与这些运算符合并(例如,true
将变为1
),空字符串或仅包含空格的字符串将变为0
。但是,这在某些情况下可能很有用。
str.repeat(count)
将变量初始化偷偷地插入提示()调用中以获取用户输入
n=prompt(i=5); // sets i=5 at the same time as getting user input
而不是使用
n=prompt();i=5;
作为副作用,它在保存1个字符的同时在提示窗口中显示输入值。
[1,2,3].join('',i=5)
保存一对大括号的情况下。
i=5,[1,2,3].join()
。
合并嵌套的for循环:
// before:
for(i=5;i--;)for(j=5;j--;)dosomething(i,j)
// after:
for(i=25;i--;)dosomething(0|i/5,i%5)
i
/的不同值的示例j
:
// before:
for(i=4;i--;)for(j=7;j--;)dosomething(i,j)
// after:
for(i=28;i--;)dosomething(0|i/7,i%7)
i*j
和分割/模数运算符检索的各个值i
和j
。
Unicode快捷方式
如果您在打高尔夫球时使用内置属性的地狱,则可以将每个属性的别名都等同于一个字符:
[Math,Number,S=String,Array].map(b=>
Object.getOwnPropertyNames(b).map((p,i)=>
b.prototype[S.fromCharCode(i+248)]=b[p]
)
)
执行完上面的代码后,您可以像这样使用它:
"foo".Č(/.*/,'bar') // replaces foo with bar
这需要118个字节,因此在某些情况下可能没有用
它可能取决于浏览器,我不确定它是否短于with(Array){join(foo),...}
或将变量定义为使用的属性,with(Array){j=join,m=map...}
但仍然值得一提。
Math Number String Array
ø toSource prototype prototype prototype
ù abs NaN quote join
ú acos POSITIVE_INFINITY substring reverse
û asin NEGATIVE_INFINITY toLowerCase sort
ü atan MAX_VALUE toUpperCase push
ý atan2 MIN_VALUE charAt pop
þ ceil MAX_SAFE_INTEGER charCodeAt shift
ÿ clz32 MIN_SAFE_INTEGER contains unshift
Ā cos EPSILON indexOf splice
ā exp isFinite lastIndexOf concat
Ă floor isInteger startsWith slice
ă imul isNaN endsWith filter
Ą fround toInteger trim isArray
ą log parseFloat trimLeft lastIndexOf
Ć max parseInt trimRight indexOf
ć min length toLocaleLowerCase forEach
Ĉ pow name toLocaleUpperCase map
ĉ random arguments normalize every
Ċ round caller match some
ċ sin search reduce
Č sqrt replace reduceRight
č tan split
Ď log10 substr
ď log2 concat
Đ log1p slice
đ expm1 fromCharCode
Ē cosh fromCodePoint
ē sinh localeCompare
Ĕ tanh length
ĕ acosh name
Ė asinh arguments
ė atanh caller
Ę hypot
ę trunc
Ě sign
ě cbrt
Ĝ E
ĝ LOG2E
Ğ LOG10E
ğ LN2
Ġ LN10
ġ PI
Ģ SQRT2
ģ SQRT1_2
À
- ÿ
,这仍然是在ISO-8859-1编码(其JS支持)每1个字节。不幸的是,在Firefox 50中,该.localeCompare
方法将放到上×
,但这通常不是问题。来源
如果要1
在循环的每次迭代中将变量初始化为(例如,在外部循环中为内部循环重置变量),例如以下内容(根据我对这个问题的回答):
for(j=n-2;p=1,j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
^^^^
由于像条件的结果j++<=n
是1
,只要它真正的,你可以直接分配的条件变量(因为当它变成假,则循环将停止执行,并会不再重要):
for(j=n-2;p=j++<=n;r|=p)for(i=1;++i<j;)p=j%i?p:0;
^^^^^^^^
您通常可以使用此方法保存2个字符。关于@ugoren
在评论这个问题的答案的想法。
再举一个例子,我还在外部for循环中使用了表达式,将这个技巧应用于我的答案w=r=++c<S.length
,总共节省了4个字符。
如果您可以接受Spidermonkey(现在)特定的脚本,则可以使用ECMAScript 6箭头功能。而不是像下面这样写代码。
a.map(function(x){return x*2}) // function? return?
您可以像这样缩短它。
a.map(x=>x*2)
如果您需要检查NaN,请不要使用isNaN(x)
,而是使用x!=x
,它更短并且也可以使用。
if(isNaN(x)){
if(x!=x){
请注意,这仅在以下情况下有效typeof(x) === "number"
:例如,如果是字符串,则isNaN("string")
返回true
,但"string" != "string"
返回false
。感谢Cyoce指出了这一点!
isNaN("string")
回报true
,而"string"!="string"
回报率false
(显然)
if(!x){
如果要进行NaN
显式检测,甚至可以使用。
x
将数字强制转换为+x!=+x
,使其等效于isNaN(x)
,但还要短2个字符。然后,+"string"!=+"string"
返回true。
n=prompt()|0
。
Math.floor
非常慢。.我几乎不应该使用。
循环提示I
您可以1
通过更改i
上次使用的时间来保存循环时的字符:
//not so god
for(i=0;i<3;i++){
alert(i);
}
//best
for(i=0;i<3;){
alert(i++);
}
注意:也可以使用--
(但请相应地修改循环以避免无限循环)
循环提示II
在某些情况下,可以通过使用递增运算符和值来保存一个字符:
for(i=0;i++<9;)
for(i=0;++i<10;)
注意:例如,您需要注意0 to -1
。和9 to 10, 99 to 100
,直到您找到一种方法来保存角色为止
^
替代!=
或==
比较为整数时,//x!=3?a:b
x^3?a:b
//x==3?a:b
x^3?b:a
//Math.ceil(n)
n%1?-~n:n
//Math.floor(n)
~~n
0|n
//Math.abs(n)
n<0?-n:n
//Math.round(n)
n+.5|0
//Math.min(x,y)
x<y?x:y
//Math.max(x,y)
y<x?x:y
-
而不是!=
整数。例如,n!=1?a:b
相当于n-1?a:b
值得注意的是,在某些情况下,您可以使用字符串代替零来在循环中保存几个字节:
s='';for(i=0;i++<9;)s+=i
for(i=s='';i++<9;)s+=i
// s="123456789", i=10
我知道Math.floor()
已经发布了替代方案,但是其他方案呢?
Math.floor(x) //before
0|x //after
Math.round(x) //before
0|x+.5 //after
Math.ceil(x) //before
x%1?-~x:x //after - credits to @Tomas Langkaas
0|x+1
如果要查找其上限的数字已经是整数,则只需加1。(大多数)安全的替代方法是0|x+1-1e9
,但这仅短了三个字节。
0|x+1-1e-9
吗?
x%1?-~x:x
(9个字符)是更好的选择。但是,就像地板替代品0|x
和一样~~x
,它仅适用于正数。
如果您正在使用三元运算符在两个数字之间进行选择,而条件是布尔值或数字 1 or 0
,则可以执行数学运算:
(x ? num1 : num2) conclusions:
1)if num1 equals num2, there ARE savings
2)if num1 is (+1) or (-1) than num2, there ARE savings
3)if either num1 or num2 equals to 0, there ARE savings
4)it is MORE LIKELY to find greater savings on num1>num2 instead of num1<num2
5)in method (*A) and (*B), savings are NOT GUARANTEED
a)num1>num2
i)(num1==(num2+1))
ex1: (x?5:4) to (x+4)
ex2: (x?8:7) to (x+7)
ii)num2==0
ex1: (x?3:0) to (x*3)
ex2: (x?7:0) to (x*7)
iii)
(*A) or (*B) //one might be shorter
b)num1<num2
i)((num1+1)==num2)
ex1: (x?4:5) to (5-x)
ex2: (x?7:8) to (8-x)
ii)num1==0
ex1: (x?0:3) to (!x*3)
ex2: (x?0:7) to (!x*7)
iii)
(*A) or (*B) //one might be shorter
c)num1==num2
i)
ex1: (x?5:5) to (5)
ex2: (x?-3:-3) to (-3)
(*A) use ((x*(num1-num2))+num2)
ex1: (x?8:4) to ((x*4)+4)
ex2: (x?4:8) to ((x*-4)+8)
ex3: (x?6:-4) to ((x*10)-4)
ex4: (x?-4:6) to ((x*-10)+6)
ex5: (x?4:-6) to ((x*10)-6)
ex6: (x?-6:4) to ((x*-10)+4)
ex7: (x?-5:-9) to ((x*4)-9)
ex8: (x?-9:-5) to ((x*-4)-5)
(*B) use ((!x*(num2-num1))+num1)
ex1: (x?8:4) to ((!x*-4)+8)
ex2: (x?4:8) to ((!x*4)+4)
ex3: (x?6:-4) to ((!x*-10)+6)
ex4: (x?-4:6) to ((!x*10)-4))
ex5: (x?4:-6) to ((!x*-10)+4)
ex6: (x?-6:4) to ((!x*10)-6)
ex7: (x?-5:-9) to ((!x*-4)-5)
ex8: (x?-9:-5) to ((!x*4)-9)
注:除了这个,你将需要删除不必要的0-
,+0
,+-
等。
注意2:有一种单独的情况,其中起作用(x) !== (x?1:0)
是x
必须的typeof === "number"
。但是,在这种情况下(-x)
效果很好。
注意3:如果您找不到节省的资金,只需使用前者(x?y:z)
以前我认为方法B永远无法击败A,但是确实存在例外:
(x?97:100) //original
(-3*x+100)
(3*!x+97)
我创建了一个github项目,为我们进行了简化(jsFiddle演示)
void 0
(它不是函数,而是关键字)不是值,它只是返回undefined
。
a
必须为1或0才能起作用
tl; dr:使用ES6功能!
Doc:https : //developer.mozilla.org/en/docs/Web/JavaScript/Reference/arrow_functions
示例:
s = x => x*x
// s = function (x) {
// return x * x;
// }
b = [s(x) for (x of a)]
。
如何在数字如何转换为布尔值的情况下比较数字:
如果要检查某物是否等于正数,则可以减去该数量并反转if
和else
块中的内容:
//simplified examples:
x==3?"y":"n"; <- 13 Chars
x-3?"n":"y"; <- 12 Chars
//expanded examples:
if(x==3){
yes();
}else{
no();
}
if(x-3){
no();
}else{
yes();
}
而且,如果您想与一个负数(*不同于-1
)进行比较,则只需要添加此数而不是减去即可。
*好,您可以肯定使用x.indexOf(y) + 1
,但是在特殊情况下,-1
您可以使用~x.indexOf(y)
来代替。
使用Mozilla的非标准“表达式闭包”功能可将许多字符保存在只需要在SpiderMonkey / Firefox或Rhino引擎中工作的脚本中。例如,
function foo(){return bar}
变成
function foo()bar
有关更多此类技巧,请参见“ 堆栈溢出”页面。
->bar
let foo = () => bar;
具有讽刺意味的是,比上面的代码短。
foo=_=>bar
甚至更短。
true
您可以使用代替编写!0
。
!1
对于false
。
1
for true
和0
for false
,除非您确实需要文字值。
转换为布尔值:
if(b){b=true}else{b=false}
b=b?true:false;
b=b?!0:!1;
b=!!b;
注:这会改变0
,""
,false
,null
,undefined
和NaN
到false
(其他一切true
)
var
)?JavaScript高尔夫代码应该是函数还是直接输出某些东西?老实说,我认为这会有所作为。