惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
Recent Announcements
Recent Announcements
阮一峰的网络日志
阮一峰的网络日志
IT之家
IT之家
A
About on SuperTechFans
量子位
Engineering at Meta
Engineering at Meta
B
Blog
The Cloudflare Blog
博客园 - 【当耐特】
Hugging Face - Blog
Hugging Face - Blog
Y
Y Combinator Blog
J
Java Code Geeks
D
DataBreaches.Net
aimingoo的专栏
aimingoo的专栏
T
Tailwind CSS Blog
H
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
Stack Overflow Blog
Stack Overflow Blog
C
Check Point Blog
酷 壳 – CoolShell
酷 壳 – CoolShell

Yusuf Aytas

When Code Is Cheap, Does Quality Still Matter? Why Crouching Tiger, Hidden Dragon Is a Masterpiece Why We Ignore Advice The Mirror Is Part of the Machine When Too Many Maps Overlap on One Person The Work Runs on Different Maps Your Work Introduces You Trial By Fire The Dude Why Headcount Math Lies Capacity Is the Roadmap The Roadmap Is Not the System Torres del Paine W Trek Escaping Status Theater Incentives Drive Everything Scaling Culture Without Dilution What Good Looks Like Why Airport Security Feels Random Why Politics Appear How to Work with Me The Janus Protocol Multi-Horizon Delivery Framework What Good Execution Looks Like Managing Your Manager Why Kingdom of Heaven’s Director’s Cut Is Better AI Broke Interviews Most of What We Call Progress Managers Have Been Vibe Coding All Along Stop Wasting Brainpower Why Over-Engineering Happens
Why I like JavaScript
Yusuf Aytas · 2018-01-07 · via Yusuf Aytas

Published · 7 min read

Every programming language has its oddities and challenges. When it comes to JavaScript, it has Every programming language has its oddities and challenges. When it comes to JavaScript, it has probably more of those oddities. It's not the just language itself but also browser support and the long tail of old decisions. Different vendors implemented slightly different JavaScript engines for years which basically meant same code, different universe. It resulted in a ton of challenges for anyone shipping real products. I dealt with these challenges myself the hard way myself. Thanks to JQuery, we had a fresh air and for a while it felt like sanity. Anyway, this isn't the end of the story because JavaScript kept evolving instead of collapsing under its own quirks. Over the years, JavaScript improved a lot, really and ES6 was the moment it stopped feeling like a necessary evil. In this post, I'll go over JavaScript weirdnesses first the ones you actually bump into and then try to explain why I like JavaScript despite all of that.

The Weird Parts

JavaScript has weird parts. Some of them are harmless trivia. Not the [] == ![] kind that people share for fun. I mean the kind that turns into a bug, then a workaround, then technical debt, then a comment you do not want to explain six months later.

Most of this weirdness is not random. It is historical. JavaScript grew inside browsers. Browsers competed. Engines behaved differently. People shipped code anyway. And once something is on the web, it is basically forever.

So when I say weird parts, I am not trying to be clever. Or provocative. I am trying to separate trivia from the stuff that actually matters. In the next section, I will go over the oddities that have practical consequences, coercion rules, equality, this, undefined, NaN. I will not over-explain them. I will directly go to code as it's better to demonstrate than talk.

// ===============================
// JavaScript Weird Parts – 2018-friendly (ES5-style)
// One file. No arrow functions. No optional chaining.
// ===============================


// Equality & coercion
0 == false;               // true
0 === false;              // false

"" == 0;                  // true
"" === 0;                 // false

null == undefined;        // true
null === undefined;       // false

[] == false;              // true
[] === false;             // false

[0] == 0;                 // true
[0] === 0;                // false

"0" == false;             // true
"0" === false;            // false


// NaN
NaN === NaN;              // false
isNaN("foo");             // true  (coercion)
Number.isNaN("foo");      // false (no coercion)
Number.isNaN(NaN);        // true


// typeof (historical baggage)
typeof null;              // "object"
typeof NaN;               // "number"
typeof [];                // "object"


// Arrays & objects doing "math"
[] + [];                  // ""
[] + {};                  // "[object Object]"
({} + []);                // "[object Object]"  // force object literal as expression

[1,2] + [3,4];            // "1,23,4"
+[];                      // 0
+[1];                     // 1
+[1,2];                   // NaN


// this depends on how, not where
var obj = {
  value: 42,
  get: function () {
    return this.value;
  }
};

var fn = obj.get;
fn();                     // undefined (or throws under strict mode if you go deeper)
obj.get();                // 42


// Strict mode flips some defaults
(function () {
  "use strict";

  function plain() { return this; }
  plain();                // undefined

  // Uncomment to see the classic implicit-global fail in strict mode:
  // function leak() { x = 10; }
  // leak();               // ReferenceError
})();


// Hoisting (var)
console.log(a);           // undefined
var a = 10;


// Function declaration hoisting vs function expression
hoisted();                // "ok"
function hoisted() { console.log("ok"); }

try {
  notHoisted();           // TypeError: notHoisted is not a function
} catch (e) {}

var notHoisted = function () { console.log("nope"); };


// delete on arrays leaves holes
var arr = [1, 2, 3];
delete arr[1];
arr;                      // [1, empty, 3]
arr.length;               // 3


// for..in on arrays is not your friend
var arr2 = [10, 20, 30];
arr2.extra = 99;

for (var k in arr2) {
  k;                      // "0", "1", "2", "extra"
}


// Floating point math
0.1 + 0.2 === 0.3;        // false
0.1 + 0.2;                // 0.30000000000000004


// parseInt surprises
parseInt("08");           // 8
parseInt("08", 10);       // 8 (be explicit)
parseInt("0x10");         // 16
parseInt("10", 2);        // 2


// Automatic semicolon insertion (ASI)
function returnsObjectWrong() {
  return
  {
    ok: true
  };
}
returnsObjectWrong();     // undefined

function returnsObjectRight() {
  return {
    ok: true
  };
}
returnsObjectRight();     // { ok: true }

We can probably find more of these peculiarities but I'll keep it short. Let's focus on the new syntax.

The Good Parts

ES6 is a significant update to the language. It introduced a powerful syntax. I have been using JavaScript fES6 is a significant update to the language. It is the point where JavaScript starts feeling like a modern language instead of a historical accident. It introduced a proper pow...y time I get to use them. So, I'll go over my favorite features and show them with code, because these are best understood by seeing them in action.

The Default Parameters

I've first used default parameters in Python and it was charming. It simplifies the code by removing extra logic to cover null cases.

function increment(i, inc = 1) {
  return i + inc;
}

The Arrow Functions

I guess it's not just me. Everbody loves arrows, it simplifies logic for filtering and mapping a lot. Note that, we have some brand new functionality like some and every. They are wonderful. You simply write less.

[1, 2, 3].map(i => i + 1).reduce((s, i) => s + i)
[1, 2, 3].filter(i => i % 2 == 0).sort()
[1, 2, 3].some(i => i % 2 == 0)
[1, 2, 3].every(i => i % 2 == 0)

The Template Strings

The template string is just better way of constructing strings. It removes the challenge to format strings. It can also evaluate the logic inside although it might not be a very good idea to do so.

let name='Gulnihal', postId=3, commentId=5
console.log(`Hello ${name}`)
let url = `https://yusufaytas.com/posts/${postId}/comments/${commentId}`
console.log(url)

Destructuring assignment

This is truly magical. You can destruct objects and arrays. You can just get the property you are looking for easily.

const [a, ...b] = [1, 2, 3]; // a becomes 1 and b becomes [2, 3]
const {id, person} = { id: 3, person: {name: 'Gulnihal'}} // id becomes 3 and person becomes {name: 'Gulnihal'}
const newArray = [1, ...[2, 3]]; //newArray becomes [1,2,3]
//You can also destruct in a for loop
const people = [{ id: 3, person: {name: 'Gulnihal'}}]
for (var {id: id, person: {name: name}} of people) {
  console.log(`The person with id=${id} is ${name}.`);
}

ES6 is a significant update to the language. It is the point where JavaScript starts feeling like a modern language instead of a historical accident. It introduced a proper module system, sane scoping with let and const, defaults that actually work, destructuring that removes boilerplate, and promises that finally made async code readable. Not syntactic sugar for the sake of it, but tools that reduce entire classes of bugs. So, I'll go over my favorite features the ones I actually reach for in real projects, and show them with code, because these are best understood by seeing them in action.

All in All

I've gone through my favorites with the new JavaScript features. There are other great features like Promises, Classes and additional object methods. However, the above features changed my daily coding significantly because I'm writing less code in a much more expressive way. In consequence, JavaScript has been the bad guy for a while but it significantly improved. One can accept weird parts and avoid them.