js的精华其实可以压缩成一点点.

三位一体: 数组, 集合, 函数

这三个其实是同一个东西

//函数, 他其实是特殊的function集合
var square = function(number) { //一般都用这个定义.
	return number * number; 
};

//集合, 看到了吗? 他仅仅是没有声明为function而已
var animal = { //大括号方式定义集合.
  type: "Invertebrates", // 属性
  displayType : function() {      console.log(this.type);  } 
}
// 数组, 他其实就是有默认序号的集合.
var arr = ['red', 'green', 'blue'];
arr.foo = "hello";

//下面的数组, 每个元素都是一个函数.
var af = [
  function(string) {  // do something
  },
  sf=function(string) {    console.log('second');  },  
]
af[1]('oo'); 
af["length"];  // 2 可以直接用中括号访问属性.
animal['displayType']();
//下面这句就通不过了, 因为[中括号]不支持键值对的这种方式声明.
var appp=[0:333, 1:5555];

//.和[]是一样的东西
var obj = {
    key1: value1,
    key2: value2
};
//Using dot notation:
obj.key3 = "value3";
//Using square bracket notation: 这里key可以是个变量. 这就是js牛的地方.
obj["key3"] = "value3";



//遍历
// for in 都可以用, 列举所有的key.
for (let i in xxx) { //会列出非整数索引.
   console.log(i); // 这里显示key.
}
// foreach, 这个只支持数组, 因此, 要把键值对的key作为数组拿出来才行.
Object.keys(obj).forEach(function(key) {

    console.log(key, obj[key]);

});

进步一丢丢: 推导式和胖箭头

// 推导式: 
var numbers = [1, 2, 3, 21, 22, 30];
var doubledEvens = [i * 2 for (i of numbers) if (i % 2 === 0)];
console.log(doubledEvens); // logs 4,44,60
// 胖箭头: 
numbers.forEach((color)=>{console.log(color);});

基于prototype的设计真的很functional

//这样就成功了, 这个递归很有趣, 函数名x并不是用来递归的名字量, 递归的名字量相反了是变量s.
Number.prototype.s = function x() { 
 var n=this.valueOf();  //主意这个this指的不是function x, 指的是调用者:number
  if ((n < 2))   return 1;
  else    return (n * (n-1).s()); //所以这里对于函数的调用应该继续使用number.s()方式, 不能使用x()方式的原因是, 这里隐式传入了调用者number作为参数, 如果用x()方式, 就米有调用者了, 没有调用者, 就没有参数了(this就指到运行环境的window了).
} ;
(5).s();

//去掉递归, 可以看这个简单的例子.
Number.prototype.r = function() {
    return Math.round(this.valueOf());
};
(5.5).r(); //第一种形式
5..r(); //第二种形式, 不能有小数点了.
5.5["r"](); //第三种当做数组属性处理的形式. 

//针对array更简单了.
var colors = ['red', 'green', 'blue'];
Array.prototype.s = function x() { 
  	this.forEach(function(color) {
 		 console.log(color);
	});
} 
colors.s();

不得不承认, 闭包是js的精华之一

//最简单例子
function makeFunc() {
    let name = "Mozilla";
    function displayName() {
        console.log(`name = ${name}`); 
    }
    return displayName;
}

let myFunc = makeFunc();
myFunc();
//此处myfunc由函数displayname和他所处的环境构成.

//更有趣的例子
function makeAdder(x) {
  return function(y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12


//更复杂的例子, return的是一个集合(有时候也翻译为对象), 他包含多个函数.

var Counter = (function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }   
})();

console.log(Counter.value()); /* logs 0 */
Counter.increment();
Counter.increment();
console.log(Counter.value()); /* logs 2 */
Counter.decrement();
console.log(Counter.value()); /* logs 1 */

此处参考: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

let可以减少闭包的使用

function showHelp(help) {
  document.getElementById('help').innerHTML = help;
}

function setupHelp() {
  var helpText = [
      {'id': 'email', 'help': 'Your e-mail address'},
      {'id': 'name', 'help': 'Your full name'},
      {'id': 'age', 'help': 'Your age (you must be over 16)'}
    ];

  for (var i = 0; i < helpText.length; i++) {
    let item = helpText[i]; 
    //let在for循环的块里面, 每次循环中他的值都不同, 并且形成作用域.
    //如果用var, 那么作用域在function setuphelp上面, 就导致了下面showhelp里面的参数item都是最后一个.
    document.getElementById(item.id).onfocus = function() {
      showHelp(item.help);
    }
  }
}

setupHelp();
//这个代码要看一会儿了. 建议有疑问去看mozilla的原文

var
声明一个变量可选择将其初始化为一个值
let
声明一个块作用域的局部变量(block scope local variable)可选择将其初始化为一个值这个就是配合闭包用的.
const
声明一个只读的常量

随便乱创建闭包是不合适的, 因为他有性能开销, 包括cpu开销和内存开销.

链式调用也是一个精华部分

虽然传统上, 我们可以通过命名函数来解决括号嵌套, 但是, 那样会导致调用代码分散. 难于从整体上把握代码的流转.

//直接声明最优写法, 优点是剥开了最大的括号. 降低了大括号的嵌套
var test = {}
test.someFunc=function () {
  console.log('someFunc111')
  return test
}
test.someOtherFunc=function () {
  console.log('someOtherFunc222')
  return test;
}
test.someFunc().someOtherFunc();

结论, 除非是要搞内置类型(才用prototype), 否则正常字面量声明是最简洁明了的.

字面量, 表达式, 初始化

//确实简洁, 大方, 美观, 符合直观感受, 我的建议是, 除了字面量之外, 不要用其他方式.
//这三个单词在js中含义差不多: 初始化器Initializer 字面量literal 表达式expressions
不论是数组
var a= [1,2]
对象
var o={1:1}
还是正则
var r=/xx/
函数
var f=function(){}

简洁

this.name = name || "";

回调函数 = 依赖注入

//回调可以说是js中最优雅的部分. 单进程, 单线程, 异步. 其他语言都掉在各种多进程, 多线程的沟里面, js没有. 逆潮流而上, 真英雄.
function doSomething(callback) {
    // Call the callback
    callback('stuff', 'goes', 'here');
}
//异步回调才是精华, 不要直接执行那个回调函数.
function doSomething(callback) {
    // 异步回调 传递参数是个技术活, 
  //1. (闭包可以解决, 匿名函数也行)这两个都是参数作用域上想办法, 
  //2. settimeout, 从第三个参数也可以传, 
  //3. 字符串传入也行但是不推荐, 开销大eval, 并且还不一定能执行大小括号要转变, 而且参数多了写法还有疑问.
    setTimeout(callback,0, 参数1, 参数2, 参数3....);  
}



promise = 异步链式回调

//很不爽, 要用promise, 需要先创建Pormise对象, 如果这个对象是返回值. 那么那他就可以链式了.
new Promise( function(resolve, reject) {...} /* executor */  );
resolve和reject分别是两个函数. 对应于匿名函数执行状态(成功/失败).

//灰常灰常不确定, 这个是否是精华, 也可能是糟粕.

集合对象的精华操作