Skip to content

Commit

Permalink
Merge branch 'gh-pages' of https://github.com/loverajoel/jstips into …
Browse files Browse the repository at this point in the history
…gh-pages
  • Loading branch information
zackhall committed Mar 1, 2016
2 parents 5b530b5 + f11025a commit 564b1a8
Show file tree
Hide file tree
Showing 53 changed files with 494 additions and 189 deletions.
24 changes: 17 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
# How to submit your tip

To submit a tip to the list, fork the repository and add your tip to a new file in the correct folder (according language). The name of the file should be `2016-xx-xx-name-of-your-tip`.
To submit a tip to the list, fork the repository and add your tip in a new file in the correct folder (according language). The name of the file should be `2016-xx-xx-name-of-your-tip`.

Use [this format](https://github.com/loverajoel/jstips/blob/gh-pages/POST_TEMPLATE.md) when writing your tip. Your tip should be readable in less than two minutes. You may add links to other sites or videos that give more insight if you wish.
Use [this format](https://github.com/loverajoel/jstips/blob/gh-pages/POST_TEMPLATE.md) when writing your tip.

Once your tip is ready, [issue a pull request](https://help.github.com/articles/using-pull-requests/) with this [PR template](https://github.com/loverajoel/jstips/blob/gh-pages/PULL_REQUEST_TEMPLATE.md) and your tip will be reviewed. Every day one tip will be merged from the available pull requests.
### Requirements
- The tip should be readable in less than two minutes
- Adding links to other sites or videos that give more insight is welcome
- Mark JS code with ```js
- Don't mention "JavaScript" in the title (as our tips are about it anyway)
- Use backticks (`) to mark code in the title ‐ _Warning_: Titles must not start with backticks!

Once your tip is ready, [issue a pull request](https://help.github.com/articles/using-pull-requests/) with this [PR template](https://github.com/loverajoel/jstips/blob/gh-pages/PULL_REQUEST_TEMPLATE.md) and your tip will be reviewed (see below).

# Notes

Leave the date and the tip number with **xx**. When we decide to merge the pull request, you will add them and squash your commits.
Leave the date and the tip number as **xx**. When the PR is `ready to merge`, we will tell you the correct numbers. Please also [squash](https://davidwalsh.name/squash-commits-git) your commits.

# Tip flow

**Tip sent** -> **Tip in review** -> **Tip Approved**
**Tip proposal****Tip under review****Tip ready to merge**

- When you send a tip, it has to pass the review process and while that happens, its status is `under review`.
- After the tip had been reviewed by 5 people and they have given their ship it emote (:shipit:), the tip is `ready to merge`.


- When you send a tip, it now has to pass the review process and while that happens, it status will be `under-review`.
- After the tip is reviewed by 5 people and they gave their :shipit:, then the tip will be `ready to merge`
We are looking forward to your contribution!
2 changes: 1 addition & 1 deletion CONTRIBUTING_zh_TW.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

當你撰寫你的 tip 時,請使用[這個格式](https://github.com/loverajoel/jstips/blob/gh-pages/POST_TEMPLATE.md)。你的 tip 應該要可以在兩分鐘內讀懂。你可以連結到其他的網站或者是影片讓我們了解更多。

當你的 tip 準備好了,依據這個 [PR 樣板](https://github.com/loverajoel/jstips/blob/gh-pages/PULL_REQUEST_TEMPLATE.md)[發送一個 PR](https://help.github.com/articles/using-pull-requests/)你的 tip 將會被校閱。每天都會有 tip 從可用的 PR 中被合併(merged)。
當你的 tip 準備好了,依據這個 [PR 樣板](https://github.com/loverajoel/jstips/blob/gh-pages/PULL_REQUEST_TEMPLATE.md)[發送一個 PR](https://help.github.com/articles/using-pull-requests/) 你的 tip 將會被校閱。每天都會有 tip 從可用的 PR 中被合併(merged)。

# 注意

Expand Down
2 changes: 1 addition & 1 deletion POST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
layout: *post

title: Demo post
tip-number: 01
tip-number: xx
tip-username: tip_js
tip-username-profile: https://twitter.com/tips_js
tip-tldr: Just a demo
Expand Down
14 changes: 7 additions & 7 deletions _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ baseurl: ""
# !! You don't need to change any of the configuration flags below !!
#

markdown: redcarpet
highlighter: pygments
permalink: /:categories/:title/

markdown: kramdown
highlighter: rouge
paginate: 10
paginate_path: "/:num/"

Expand Down Expand Up @@ -142,16 +142,16 @@ transl:
menu:
home:
txt: 首頁
link: /
link: /zh_TW
about:
txt: 關於
link: /zh_TW/about
subscribe:
txt: 訂閱
submit_your_tip:
txt: 提交你的小知識
txt: 提交你的 tip
link: https://github.com/loverajoel/jstips/blob/gh-pages/CONTRIBUTING_zh_TW.md
footer_subscribe_message: 訂閱更多更棒的每日小知識
footer_subscribe_message: 訂閱更多更棒的每日 tips
footer_placeholder_subscribe: your@email.com
arrow_prev: 上一篇小知識
arrow_next: 下一篇小知識
arrow_prev: 上一篇 tip
arrow_next: 下一篇 tip
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ You just have to concat everything into an array first. `Array.concat` will acce

```javascript
function printUpperCase(words) {
var elements = [].concat(words);
var elements = [].concat(words || []);
for (var i = 0; i < elements.length; i++) {
console.log(elements[i].toUpperCase());
}
}
```

`printUpperCase` is now ready to accept a single node or an array of nodes as its parameter.
`printUpperCase` is now ready to accept a single node or an array of nodes as its parameter. It also avoids the potential `TypeError` that would be thrown if no parameter was passed.

```javascript
printUpperCase("cactus");
Expand Down
92 changes: 80 additions & 12 deletions _posts/en/2016-01-18-rounding-the-fast-way.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,105 @@
---
layout: post

title: Rounding the fast way
title: Truncating the fast (but risky) way
tip-number: 18
tip-username: pklinger
tip-username-profile: https://github.com/pklinger
tip-tldr: Today's tip is about performance. Ever came across the double tilde `~~` operator? It is sometimes also called the double NOT bitwise operator. You can use it as a faster substitute for `Math.floor()`. Why is that?
tip-tldr: `~~X` is usually a faster `Math.trunc(X)`, but can also make your code do nasty things.

categories:
- en
---

Today's tip is about performance. [Ever came across the double tilde] (http://stackoverflow.com/questions/5971645/what-is-the-double-tilde-operator-in-javascript) `~~` operator? It is sometimes also called the double NOT bitwise operator. You can use it as a faster substitute for `Math.floor()`. Why is that?
This tip is about performance...with a hidden price tag.

One bitwise shift `~` transforms the 32 bit converted input into `-(input+1)`. The double bitwise shift therefore transforms the input into `-(-(input + 1)+1)` making it a great tool to round towards 0. For numeric input, it therefore mimics the `Math.ceil()` for negative and `Math.floor()` for positive input. On failure, `0` is returned, which might come in handy sometimes instead of `Math.floor()`, which returns a value of `NaN` on failure.
Have you ever come across the [double tilde `~~` operator](http://stackoverflow.com/questions/5971645/what-is-the-double-tilde-operator-in-javascript)? It's also often called the "double bitwise NOT" operator. You can often use it as a faster substitute for `Math.trunc()`. Why is that?

```javascript
One bitwise shift `~` first truncates `input` to 32 bits, then transforms it into `-(input+1)`. The double bitwise shift therefore transforms the input into `-(-(input + 1)+1)` making it a great tool to round towards zero. For numeric input, it therefore mimics `Math.trunc()`. On failure, `0` is returned, which might come in handy sometimes instead of `Math.trunc()`, which returns `NaN` on failure.

```js
// single ~
console.log(~1337) // -1338

// numeric input
console.log(~~47.11) // -> 47
console.log(~~-12.88) // -> -12
console.log(~~1.9999) // -> 1
console.log(~~3) // -> 3
```

However, while `~~` is probably a better performer, experienced programmers often stick with `Math.trunc()` instead. To understand why, here's a clinical view on this operator.

### INDICATIONS

##### When every CPU cycle counts
`~~` is probably faster than `Math.trunc()` across the board, though you should [test that assumption](https://jsperf.com/jsfvsbitnot/10) on whichever platforms matter to you. Also, you'd generally have to perform millions of such operations to have any visible impact at run time.

##### When code clarity is not a concern
If you're trying to confuse others, or get maximum utility from your minifier/uglifier, this is a relatively cheap way to do it.

### CONTRAINDICATIONS

##### When your code needs to be maintained
Code clarity is of great importance in the long term, whether you work in a team, contribute to public code repos, or fly solo. As [the oft-quoted saying](http://c2.com/cgi/wiki?CodeForTheMaintainer) goes:
> Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.
For a solo programmer, that psychopath is inevitably "you in six months".

##### When you forget that `~~` always rounds to zero
Newbie programmers may fixate on the cleverness of `~~`, forgetting the significance of "just drop the fractional portion of this number". This can easily lead to **fencepost errors** (a.k.a. "off-by-one") when transforming floats to array indices or related ordinal values, where a different kind of fractional rounding may actually be called for. (Lack of code clarity usually contributes to this problem.)

For instance, if you're counting numbers on a "nearest integer" basis, you should use `Math.round()` instead of `~~`, but programmer laziness and the impact of **_10 whole characters saved per use_** on human fingers often triumph over cold logic, leading to incorrect results.

// on failure
console.log(~~[]) // -> 0
In contrast, the very names of the `Math.xyz()` functions clearly communicate their effect, reducing the probability of accidental errors.

##### When dealing with large-magnitude numbers
Because `~` first does a 32-bit conversion, `~~` results in bogus values around &plusmn;2.15 billion. If you don't properly range-check your input, a user could trigger unexpected behavior when the transformed value ends up being a great distance from the original:
```js
a = 2147483647.123 // maximum positive 32-bit integer, plus a bit more
console.log(~~a) // -> 2147483647 (ok)
a += 10000 // -> 2147493647.123 (ok)
console.log(~~a) // -> -2147483648 (huh?)
```
One particularly vulnerable area involves dealing with Unix epoch timestamps (measured in seconds from 1 Jan 1970 00:00:00 UTC). A quick way to get such values is:
```js
epoch_int = ~~(+new Date() / 1000) // Date() epochs in milliseconds, so we scale accordingly
```
However, when dealing with timestamps after 19 Jan 2038 03:14:07 UTC (sometimes called the **Y2038 limit**), this breaks horribly:
```js
// epoch timestamp for 1 Jan 2040 00:00:00.123 UTC
epoch = +new Date('2040-01-01') / 1000 + 0.123 // -> 2208988800.123

// back to the future!
epoch_int = ~~epoch // -> -2085978496
console.log(new Date(epoch_int * 1000)) // -> Wed Nov 25 1903 17:31:44 UTC

// that was fun, now let's get real
epoch_flr = Math.floor(epoch) // -> 2208988800
console.log(new Date(epoch_flr * 1000)) // -> Sun Jan 01 2040 00:00:00 UTC
```

##### When the original input wasn't sanitized
Because `~~` transforms every non-number into `0`:
```js
console.log(~~[]) // -> 0
console.log(~~NaN) // -> 0
console.log(~~null) // -> 0

// greater than 32 bit integer fails
console.log(~~(2147483647 + 1) === (2147483647 + 1)) // -> 0
```
some programmers treat it as alternative to proper input validation. However, this can lead to strange logic bugs down the line, since you're no longer distinguishing between invalid inputs and actual `0` values. This is therefore _not_ a recommended practice.

##### When so many people think `~~X == Math.floor(X)`
Most people who write about "double bitwise NOT" incorrectly equate it with `Math.floor()` for some reason. If you can't write about it accurately, odds are good you'll eventually misuse it.

Others are more careful to mention `Math.floor()` for positive inputs and `Math.ceil()` for negative ones, but that forces you to stop and think about the values you're dealing with. This defeats the purpose of `~~` as a handy no-gotchas shortcut.

### DOSAGE
Avoid where possible. Use sparingly otherwise.

Although `~~` may perform better, for the sake of readability please use `Math.floor()`.
### ADMINISTRATION
1. Apply cautiously.
2. Sanitize values before applying.
3. Carefully document relevant assumptions about the values being transformed.
4. Review code to deal with, at minimum:
* logic bugs where invalid inputs are instead passed to other code modules as valid `0` values
* range errors on transformed inputs
* fencepost errors due to incorrect rounding direction
10 changes: 5 additions & 5 deletions _posts/en/2016-01-27-short-circuit-evaluation-in-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,20 @@ The logical OR could also be used to set a default value for function argument.

```js
function theSameOldFoo(name){
name = name || 'Bar' ;
console.log("My best friend's name is " + name);
name = name || 'Bar' ;
console.log("My best friend's name is " + name);
}
theSameOldFoo(); // My best friend's name is Bar
theSameOldFoo('Bhaskar'); // My best friend's name is Bhaskar
```
The logical AND could be used to avoid exceptions when using properties of undefined.
Example:-
Example:

```js
var dog = {
bark: function(){
console.log('Woof Woof');
}
console.log('Woof Woof');
}
};

// Calling dog.bark();
Expand Down
2 changes: 1 addition & 1 deletion _posts/en/2016-02-15-detect-document-ready-in-pure-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ if (document.readyState === 'complete') {
}
```

You can detect when the document it's ready...
You can detect when the document is ready...


```js
Expand Down
44 changes: 44 additions & 0 deletions _posts/zh_CN/2016-02-26-extract-unix-timestamp-easily.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
layout: post

title: 简单获取unix时间戳
tip-number: 49
tip-username: nmrony
tip-username-profile: https://github.com/nmrony
tip-tldr: 在Javascript里,你可以简单的取得unix时间戳

categories:
- zh_CN
---

我们经常需要使用unix时间戳计算。有很多方法可以取得unix时间戳。目前取得unix时间戳最简单最快的方法是:

```js
const timestamp = Date.now();
```

```js
const timestamp = new Date().getTime();
```

要取得一个具体时间的unix时间戳,将`yyyy-mm-dd`作为参数传递给`Date`构造函数。例如

```js
const timestamp = new Date('2012-06-08').getTime()
```
你还可以像下面一样,在声明`Date`对象的时候添加一个`+`

```js
const timestamp = +new Date()
```
或者对于具体时间

```js
const timestamp = +new Date('2012-06-08')
```
在底层,运行时调用了`Date`对象的`valueOf`方法。然后一元操作符`+`调用了之前返回值的`toNumber()`方法。想要了解更多内容请参考下面链接

* [Date.prototype.valueOf](http://es5.github.io/#x15.9.5.8)
* [Unary + operator](http://es5.github.io/#x11.4.6)
* [toNumber()](http://es5.github.io/#x9.3)
Loading

0 comments on commit 564b1a8

Please sign in to comment.