1995 Brendan Eich(布兰登*艾奇)发明了javascript,现任Mozilla公司CTO.

  • H5可以允许其多线程,但只能有一个线程操作DOM!
  • js运行时都包含了一个任务队列,其上的每个任务(异步任务)都有对应的回调函数(可能代码相同).
  • 所有的同步任务都在栈上执行,当栈中代码执行完毕,主线程才去任务队列中取(FIFO)任务放到主线程执行.
  • 编译器预处理步骤:
    • 查找所有函数,包括递归的内部函数, 但不包括var声明的函数, 并解析其定义!
    • 查找所有var声明的变量, 直接用=声明并赋值的变量不会被编译器优先识别! 注意: 仅是声明,此时还不会执行赋值动作!
  • undefined(undefined对象) null(object对象) boolean number string object(function...)

basic

  // js中的整数有个上限:Number.MAX_SAFE_INTEGER:9007199254740991(16位).其实都是用double类型保存的,所以精度上有损失(小数点后最多16位精度).
  var foo = require('/home/user/foo.js')  // 可以被多次导入,但仅会被初始化一次
  var b = c = 2;  // window.c
  var a = [];
  console.log(typeof(a));
  // 绝大多数场合应该使用 ===, 因为如下表达式的值都为true: '2'==2 && 0=='' && 1==true && null==undefined!
  // false: undefined null '' 0 NaN
  // undefined: 不存在或没有赋值或void(0): 1+undefined-->NaN;  ''+undefined-->undefined
  // null:  1+null-->1;  1*null-->0;  ''+null-->'null'
  isNaN(a) == true;  // 注意:如果是字符串,还会尝试能不能转换为数字!
  parseInt(a);  // NaN.
  for (var i=0; i<10; i++) {  // 如果是let(let可看成局部的),结果为6!
    // 此处的a[i]只登记了地址!
    a[i] = function(e) { // 相当于内部 var e;
      // 被调用的时候才解释执行(找i的值),此时其值已被改变! 链式查找,优先查找最近的作用域,最后才去window找!
      console.log(i);
      console.log(b);
      var b;  // 会在函数的所有代码执行之前被声明!
      a = 1;  // 认为是全局变量,如果全局中没有则会创建window.a
    };
  }

string

  text = "Hello"; text.length == 5;
  // 以下操作均不改变原有字符串!
  text.charAt(index); substring(start, end); concat(str,str1..) trimLeft();trimRight();trim();
  indexof(str, start); replace(regex, rep/*可使用$1这些*/); search(regex); toUpperCase(); split(dlim, limit=-1);
  slice(startIndex, endIndex:默认结尾);  // substring()与其一样,只是会视负数为0(若右侧变0后小,会交换);
  substr(startIndex, count)  // 同slice,只是第二个参数是count,-3会与长度相加.
  str = JSON.stringify(obj);  // obj --> string,会忽略函数,原型,与undefined成员!
  JSON.parse(str);  // str --> obj
  encodeURI(`http://...?query=${var}`)
  decodeURI('http://...?query=%E7%90%86%E8%A7%A3');

date

  var d = new Date("July 21, 1983 01:15:00");  // 如果为空则为系统时间,内部会调用parse()!返回从'1970/01/01 -> 2005/07/08'之间的毫秒数
  d = new Date(Date.UTC(2005,4,5,17,55,55));  // 2005年5月5日...
  d.now();  // 当前时间的毫秒数
  d.getDate();     // 0-31此处返回的是 21
  d.getDay();      // 0-6, 周末是 0
  d.getMonth();    // 0-11,此处返回的是 6(7月)
  d.getFullYear(); // xxxx, 此处返回的是 1983
  d.getHours();    // 0-23, 此处返回的是 1
  d.getMinutes();  // 0-59, 此处返回的是 15
  d.getSeconds();  // 0-59, 此处返回的是 0
  d.getMilliseconds(); // 0-999
  d.toTimeString();    // "01:15:00"
  d.toDateString();    // "21"
  d.setDate(d.getDate() - 7);  // 上周
  document.write(d/(1000*60*60*24*365));  // 转换成年,document. == this.

  var ci = setInterval(func, 1000);  // 每秒执行函数func
  clearInterval(ci);
  var t = setTimeout(func, 1000);  // 1秒后执行参数1中的语句.不会重复.
  clearTimeout(t);  // 清除计时器,必须在1秒钟前.

array

these members change the original array: push,pop,shift,unshift,splice,sort,reverse

  var cars = new Array('Saab')  // Array(3):表指定维度为3,每个元素都是undefined; Array(3, 'hello'):表存俩个元素,类型随意
  Array.isArray(cars);
  car.push('leiz', 1)  // ['Saab', 'leiz', 1],返回新数组的长度.也可使用a[index]=val来插入数值,中间空的会undefined.
  car.pop()  // 删除并返回数组中的最后1个元素; warning: array will be changed
  car.unshift(0)  // 向队列开头添加1个的元素,返回新数组的长度
  car.shift()  // 删除并返回数组中的开头元素
  car.toString()  // 转换为字符串: 'Saab,leiz'
  car.indexOf('leiz', startIndex=0)  // 1,第1个查找的值所在的索引,类比lastIndexOf()!
  cars.length == 2
  cars.join("-")  // warning: do not change the original array!
  for (var i in cars) {
    // 字典:遍历的是key, 对象:遍历的是属性
  }
  var a = [1, 2, ...cars]  // ...可用来解包{}和[]
  a.reverse()
  a.concat(4,5,[6,7])  // 3,2,1,4,5,6,7; warning: do not change the original array!
  a.slice(startIndex, end)  // 参看string::slice即可; warning: do not change the original array!
  a.splice(start, delCount, value)  // 拼接的意思. splice(1,1,v):替换第2个元素,返回原值.不写v是删除.count=0是插入!
  a.sort()  // 以字符串比较/数值方法对数组进行排序,可以加个函数function(a,b){}控制排序的规则
  a.some(f(item,index,array){})  // f(每项),只要有1项f运算返回true,则返回true!
  a.every(f)  // f(每项)都返回true,才返回true.
  a.filter(f) // f(每项),返回[f后等于true的成员]. forEach()没有返回动作. warning: do not change the original array!
  a.map(f)    // f(每项),返回[f调用后的结果]
  a.reduce(f(prev,cur,index,array){ // 第1次prev=a[0],cur=a[1];第2次prev=上次f的返回值,cur=a[2]... warning: do not change the original array!
    return prev + cur.done ? 1 : 0
  })

Dict/Object

对象可以随时随时添加属性.属性也可以是方法!
属性的访问: o.attrname; o['attrname']; for attr in o ...

  // 创建对象1
  var person = new Object();  // 或者-->
  person = {firstname:"bill", lastname:"gates", id : process.env.sys_env_name || 1};
  person.firstname = "leizi";
  person["lastname"] = "hello";  // 可动态添加属性,括号中可以是变量!
  person.eyecolor = "blue";
  // 或者 -->
  function Person(name, age) {
    this.name = name;  // 对象属性,其中的每个属性都是对象上的.
    this.age = age;  // 其实属性名也可以是数值,会转化为字符串
    this.friends = ['leiz', 'rong'];
    // 仅会在属性sayName不存在时调用一次,添加到原型中
    if (typeof this.sayName != 'function') {
       Person.prototype.sayName = function() {}
    }
  }
  // 定义原型:需要共享的部分,类属性.
  Person.prototype = { // p.__proto__.newMember
    constructor : Person;
    name : "Nicholas",  // 这些直接添加到原型对象中(共享的),创建对象时会先查找对象属性,找不到才查找此处的原型.
    age : 29,
    sayName : function () { /* 这里面的this也可指代调用的对象 */ }
  };
  p = new Person('leiz', 20);  // 创建对象,以构造函数的形式!
  p instanceof Person;  // true
  'name' in p;  // true
  p.hasOwnProperty('name');  // false
  Object.getPrototypeOf(p).name == Person.prototype.name;  // 访问的属性不存在时返回undefined
  // 如果传入的是对象,则返回的是对象的属性.getOwnPropertyNames()只获得对象的属性.
  Object.keys(Person.prototype);  // ['name', 'age', 'job', 'sayName']

math

  var num = 8;
  num.toString(8);  // 以8进制转换为字符串
  num.toFixed(2);  // 转换为字符串,保留2位小数,没有补零,四舍五入.
  var pi_value = Math.PI;
  var sqrt_value = Math.sqrt(15);
  Math.round(-4.40) // -4
  Math.random()     // 0-1
  Math.max(-3,7.3)  // 7.3

regexp

注意: 以下两种写法在ECMAScript5以下有点不同:
构造函数方法会每次新生成.而第一种方法即使在循环内部也仅生成1次!

  var reg = /.at/gi;  // 匹配所有以at结尾的三个字符,不区分大小写.或-->
  var reg = new RegExp(".at", gi);
  reg.test("hello world!");  // 返回false,未找到'e'.注意:第2次调用会接着上次找到的位置后面(.lastIndex属性,若已测到尾部则折回)!
  reg.exec("leizi");  // [匹配到的整个字符串, 第1个捕获组匹配到的内容=.$1, .., index:匹配的位置, input:..],没有匹配到返回null!
  reg.compile("h");  // 改变检索模式,匹配字符'h'

function

闭包中的匿名函数比较特殊:具有全局特性!其中的this通常指代window对象,而不是常规调用者.

  async function f(p1, p2) {
    arguments.length;  // 也可以用来访问修改参数,索引访问.
    try {
      doSomething();
      // throw "some msg"
    } catch (e) {
      txt += "Error description: " + e.message + "\n\n"
      alert(txt);
    }
    // await迫使func1同步执行,只能用在async函数内部!
    await func1().catch(e => {})  // 简单的捕捉并处理错误
    return p1 * p2;  // 返回值成为then的参数,返回值必然是个Promise,默认会await(p1*p2)转换!
  }
  f(1,2).then(
    v => console.log(v)
  ).then(
    e => console.log(e)
  )

  /* lambda */
  // 注意: 只有一个参数时可以省略`()`, 但当没有参数时,必须用括号`()`!
  p => v  // 等价于 p => { return v }.
  (p1, p2) => {}  // 等价于 function(p1,p2){}.

BOM

  window.innerWidth;   // 内页宽度 window.innerHeight;
  window.open()        // 打开新窗口 window.close()  // 关闭当前窗口
  window.moveTo()      // 移动当前窗口
  window.resizeTo()    // 调整当前窗口的尺寸
  location.hostname    // web主机的域名
  location.port        // 端口,没有时返回''
  location.protocol    // http:// 或 https://
  location.pathname()  // /js/js_window_location.asp
  location.search      // 搜索参数?=.....
  location.href        // 当前页面的URL
  location.assign()    // 加载新的文档或网址
  location.reload()    // 加载新的文档或网址
  history.back()       // history.go(-1)
  history.forward()    // history.go(1)
  navigator.platform   // Win32
  navigator.systemLanguage() // zh-cn
  navigator.cookieEnabled()  // true
  screen.availWidth    // 可用的屏幕宽度,浏览器的水平像素
  screen.availHeight   // 可用的屏幕高度(除去任务栏)
  confirm() // 确认框,确认:true  alert()
  prompt()  // 用户需要输入某个值,确认:返回值为输入的值;取消:null

DOM

如果在文档已完成加载后执行 document.write 整个HTML页面将被擦除重写

https://www.runoob.com/jsref/prop-html-innerhtml.html
http://www.w3school.com.cn/js/jsref_events.asp

  node = document.createElement("p");  // 添加新的段落,类似于tinyxml
  node.appendChild(document.createTextNode("新段落的文字"));  // 将文字节点连接到段落
  node = document.getDocumentById("idname").insertAdjacentHTML('beforeEnd','<p><input type='text'></p>');
  node.innerText = "";  // 修改标签的内容(value)
  node.onclick = function(){}  // 时候绑定,省的HTML中每个标签均指定事件了!
  node = document.getElementByTagName(tagname).parentElement.lastElementChild;
  node.removeChild(child);
  node.setAttribute('attrname', 'value');  // getAttribute,removeAttribute
  node.className;  // 'class class1',返回的是一个字符串
  node.classList.add('class2');  // classList返回的是一个list
  node.addEventListner('click', function(){}, true);  // true:从外层向里层响应顺序.默认是冒泡即相反.

  // event
  document.onkeypress = function(event) {
    event.keyCode;  // 65:表按下'A'键
  }

http use Ajax or jQuery

  var xhr = XMLHttpRequest();
  xhr.onreadystatechange = function() {
    // 4:数据返回完整 3:只有一部分返回 2:有调用send 1:有调用open 0:未初始化(未调用open)
    if (xhr.readyState == 4) {
      console.log(xhr.responseText);
    }
  }
  xhr.open('open', '01.php');
  xhr.send(null);  // 若是post请求则给出请求的数据!

  // jquery
  $.ajax(
    url:  '/host',
    type: 'POST',
    data: $('#formid').serialize(),  // 省的一个个取赋值
    traditional: true,  // 防止data中的list不能被正确处理
    success: function(data) {
      var r = JSON.parse(data);  // 服务器那边一般是HttpResponse(json.dumps({...}))
    }
  )

jQuery

http://jquery.cuishifeng.cn/

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js">;</script>

  input[attrname^='text'] {}  /* 标签+属性选择器(^=表开头,$=表结尾,*=表包含),*[]表示所有标签的属性限制 */
  body, head {} /* 组合选择器:或的关系.属性[]也可用在此处或下面 */
  div span {}   /* 层级选择器:div下面的所有span,递归 */
  div > span {} /* 层级选择器:div下面的span,不递归 */
  #id_name {}   /* id不能重复,所以一般用在特例上 */

  .class_name :hover {}
  .c:first  // 第1个
  .c:eq(2)  // 索引位置的第3个
  .c :text  // input的text控件 == .c input[type='text']; password radio checkbox submit reset button file image
  $(':checkbox').prop('checked', true);  // 全选,prop同attr,但专门用于checkbox+radio!
  $(':checkbox').each(function(index) {  // 反选
    this.checked = !this.checked;  // 此时的this指代当前循环的dom对象,$后可转换为jQuery对象.
  })
  // == on/bind('click', function...) | off/unbind.
  // .delegate('li', 'click', function...) :更牛逼,可以给动态创建的子元素绑定委托(点击的时候才执行代码).
  $('#id').click(function() {
    // prev parent children siblings nextAll prevUntil eq.
    $(this).next().addClass('left').find('.c').removeClass('left').text();
    .hasClass('c1').toggleClass('c1');  // 有则移除,没有则添加
    .text('setvalue');
    .val();  // input控件当前值,等价于DOM中的.value!
    .attr('attrname');  // 获取属性值;俩参时:属性不存在会添加,值不一样会修改!removeAttr()
    .css('color','green').append('<li>2</li>');  // prepend after(另起一个ul)
    .eq(1).remove();  // 删除DOM标签. empty(清空内容)
  )
  .offset().left()  // 标签坐标,相对于window. position:相对于父标签
  .scrollTop(0)     // 滚动条,最上头
  .extend({  // jQuery扩展,类似于$.ajax,可以直接$.func()调用.
    'fun' : function(){}
  })

  $.cookie('key')