ns

notes

View on GitHub

JavaScript 语言精髓

类型

变量

// 声明
var a = 1; // 函数作用域, 变量提升
let b = 2; // 块作用域
const c = 3; // 块作用域
d = 4; // 全局作用域

块级作用域实现

/* ES5 */
try {
  throw 1;
} catch (a) {
  alert(a); // 1
}
alert(a); // is not defined

变量提升

function fn() {
  if (false) {
    var a = 1;
  }
  alert(a);
}
// 相当于
function fn() {
  var a; // var为函数级作用域
  if (false) {
    a = 1;
  }
  alert(a); // undefined
}

函数

// 函数声明提升优先
console.log(typeof v); // function
var v = 9;
console.log(typeof v); // number
function v() {}
console.log(typeof v); // number
// 等于:
function v() {}
var v;
console.log(typeof v); // function
v = 9;
console.log(typeof v); // number
console.log(typeof v); // number
// 严格模式 限制内部直接出现的`this`隐式指window
(function f() {
  "use strict";
  function fn() {
    console.log(this); // undefined
  }
  fn();
})();
//----------------------------------
function fn() {
  console.log(this); // window
}
(function f() {
  "use strict";
  fn();
})();
// 块级函数名保护
function f() {
  f = 1;
}
f();
console.log(typeof f); // number
console.log(typeof f); // number
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
{
  function f() {
    f = 1;
  }
  f();
  console.log(typeof f); // number
}
console.log(typeof f); // function
// 函数作表达式时外部不可获取函数名
if (function f() {}) {
  console.log(typeof f); // undefined
}
//----------------------------------------
var fn = function f() {
  // 内部可获取
  console.log(typeof f); // function
};
console.log(typeof f); // undefined
fn();
//----------------------------------------
(function f() {
  console.log(typeof f); // function
})();
console.log(typeof f); // undefined

闭包垃圾回收

function fn() {
  var a = 1; // 回收
  return function() {
    alert(1);
  };
}

// eval: 不对LexicalEnvironment进行任何的解绑
function fn() {
  var a = 1; // 不回收
  return function() {
    eval(""); // 因为无法静态分析
  };
}

function fn() {
  var a = 1; // 回收
  return function() {
    window.eval("");
  };
}

// with: 放弃全部变量的回收
var outter = {
  age: 20
};
with (outter) {
  name = "name";
}
console.log(name); // name

// try..catch(ex): 不会回收ex
// ex是未定义变量 -> 延长了作用域链, 引用LexicalEnvironment
try {
  throw new Error("");
} catch (ex) {}

// new Function(" "): scope LexicalEnvironment
// new Function(字符串) 绑定全局
var test = "outter";
function init() {
  var test = "inner";
  var fn = new Function("console.log(test)");
  fn(); // outer
}
init();
// new Function(立即执行的函数) 绑定当前
var test = "outter";
function init() {
  var test = "inner";
  new Function(console.log(test)); // inner
}
init();

原型链

function fn() {
  this.a = 1;
}
fn.prototype.a = 2;
var obj = new fn();
alert(obj.a); // 1  constructor优先(fn.prototype.constructor === fn)
function P() {}
var c = new P();
c.__proto__ === P.prototype;

原型链

继承

子类得到父类属性、方法, 且保留 constructor

作用域链

var name = "global";
function A(name) {
  alert(name);
  this.name = name;
  var name = "1";
}
A.prototype.name = "2";
var a = new A("3"); // '3'

alert(a.name); // '3'
delete a.name; // -> delete a.__proto__.name
alert(a.name); // '2'
function fun(n, o) {
  console.log(o);
  return {
    fun: function(m) {
      return fun(m, n);
    }
  };
}

var a = fun(0);

a.fun(1);
a.fun(2);

var b = fun(0)
  .fun(1)
  .fun(2)
  .fun(3);

var c = fun(0).fun(1);

c.fun(2);
c.fun(3);

this

指向调用者

function test() {
  alert(this.m === undefined);
}
test(); // true, 指向window
window.test(); // true, 指向window

this.m = 1000;
var o = {
  m: 500,
  test: function() {
    alert(this.m);
    return function() {
      alert(this.m);
    };
  }
};
var f = o.test(); // 500, 指o
f(); // 1000, 指window