/*
* 1. 先声明一个变量a,没有赋值(默认值谁undefined)
* 2. 在当前作用域中开辟一个位置存储12这个值
* 3. 让变量a和12关联在一起(定义:赋值)
*/
var a = 12
var b = a;
b = 13;
console.log(a);
var ary1 = [12, 23];
var ary2 = ary1;
ary2.push(100);
console.log(ary1)
function sum() {
var total = null;
for(var i = 0; i< arguments.length; i++;) {
var item = arguments[i];
item = parseFloat(item);
!isNaN(item) ? total += item : null;
}
return total;
}
console.log(sum(12, 23, '34', 'AA'))
堆内存:引用值对应的空间
变量提升: 当栈内存(作用域)形成,js代码自上而下执行之前,浏览器首先会把所有带va r/function关键词进行提前“声明”或者“定义”,这种预先处理机制称为“变量提升”
声明:(declare):var a/ function sum
定义:(defined)a= 12 (定义其实就是赋值操作)
在变量提升阶段:
1. 带“var”的只声明未定义
2. 带“function”的声明和赋值都完成了
var a = 12
var b = a;
b = 13;
console.log(a);
var ary1 = [12, 23];
var ary2 = ary1;
ary2.push(100);
console.log(ary1)
function sum() {
var total = null;
for(var i = 0; i< arguments.length; i++;) {
var item = arguments[i];
item = parseFloat(item);
!isNaN(item) ? total += item : null;
}
return total;
}
console.log(sum(12, 23, '34', 'AA'))
在全局作用域下声明一个变量,也相当于给window全局设置了一个属性,变量的值就是属性值(私有作用域中的声明的私有变量和window没啥关系)
console.log(a) // undefined
console.log(window.a) // undefined
console.log('a' in window) // true 在全局作用域中声明了一个变量a,此时就已经把a当成属性赋值给window了,只不过此时还没有给a
//赋值,默认值undifined in:检测某个属性是否隶属于这个对象
var a = 12; // 全局变量值修改,window的属性值也跟着修改
console.log(window.a) // window的一个属性名a 12
a = 13
console.log(window.a) // 13
window.a = 14;
console.log(a) // 14
以上例子说明:全局变量和window中的属性存在“映射机制”
**
不加var的本质是window的属性
如下面例子:
console.log(a) // Uncaught ReferenceError: a is not defined
console.log(window.a) // undefined
console.log('a' in window) // false
a = 12 // window.a = 12
console.log(a) // 12
console.log(window.a) // 12
var a = 12,
b = 13; // 这样写b是带var的
var a = b = 12; // 这样写b是不带var的
私有作用域中带var和不带var也有区别:
console.log(a, b) // undefined , undefined
var a = 12,
b = 12;
function fn() {
console.log(a, b) // undefined, 12
var a = b = 13
console.log(a, b) // 13 13
}
fn();
console.log(a, b) // 12, 13
function fn() {
b= 13;
console.log('b' in window) // true,在作用链查找的过程中,如果找到window也没有这个变量,相当于给
// 给window设置了一个属性b(window.b = 13)
console.log(b)
}
console.log(b)
/*
* 变量提升:
* var fn; 只对等号左边进行变量提升
**/
sum();
fn(); // Uncaught TypeError: fn is not a function
// 匿名函数之函数表达式
var fn = function () {
console.log(1)
}
// 普通函数
function sum() {
console.log(2)
}
在当前作用域下,不管条件是否成立都要进行变量提升
/**
* 在当前作用域下,不管条件是否成立都要进行变量提升
* 带var的还只是声明
* 带function的在老版本浏览器渲染机制下,声明+定义,但是为了迎合ES6中的块级作用域,新浏览器对于函数(在条件判断中的函数)
是否成立,都只是先声明,没有定义,类似var
*/
console.log(a) // undefined
if(1 === 2) {
var a = 12
}
console.log(a) //undefined
//在全局作用域下声明的全局变量也相当于给window设置了一个属性
console.log(a) //undefined
if('a' in window) {
var a = 100
}
console.log(a) // 100
f= function () {
return true;
}; // window.f = ....
g = function () {
return false
}; // window.g = ...
~function() {
/*
* 变量提升:
* function g; g是私有变量
*/
if(g() && ([] == ![])) { // Uncaught TypeError: g is not a function [] == ![] => 0 == 0
// 把全局中的f进行修改
f= function () {
return false
};
function g() {
return true;
}
}
}()
console.log(f());
console.log(g());
/*
* 全局下变量提升
* function fn
*/
console.log(fn) // undefined
if(1 === 1) {
console.log(fn)
function fn() {
console.log('ok')
}
}
console.log(fn) //函数本身
fn(); // 4
function fn() {
console.log(1);
}
fn(); // 4
function fn() {
console.log(2);
}
fn(); // 4
var fn = 100 // 带var的在提升阶段只把声明处理了,赋值操作没处理,所在在代码执行的时候需要完成赋值100
fn(); // Uncaught TypeError: fn is not a function
function fn() {
console.log(3);
}
fn();
function fn() {
console.log(4);
}
fn();
console.log(a) //Uncaught ReferenceError: a is not defined
let a = 12;
console.log(window.a) // undefined
console.log(a) // 12
//-------------
let a = 10,
b = 10
let fn =function () {
// console.log(a, b) //Uncaught ReferenceError: a is not defined
let a = b = 20
console.log(a, b) // 20, 20
}
fn();
console.log(a, b) // 10, 20
//-------------
let a = 12
console.log(a)
let a = 13 // Uncaught SyntaxError: Identifier 'a' has already been declared
console.log(a)
var a = 12;
if(true) {
console.log(a)
let a = 13
}
//--------
console.log(typeof a) // "undefined" 在原有浏览器渲染机制下,基于typeof等逻辑运算符检测一个未被声明的
// 变量不会报错,返回undefined
//--------
console.log(typeof a) // Uncaught ReferenceError: a is not defined
let a //如果当前变量是基于es6语法处理,在没有声明这个变量的时候,使用typeof检测会直接报错,不会是undefined,解决了原有的js死区问题
在私有作用域中,只有以下两种情况是私有变量:
剩下的都不是自己私有变量,都需要基于作用域链的机制向上查找
var a = 12,
b = 13,
c = 14;
function fn(a) {
/*
* 行参赋值 a = 12
* 变量提升: var b
* 在私有作用域中,只有以下两种情况是私有变量
* 1.声明过的变量(带var/function)
* 2.行参也是私有变量
* 剩下的都不是自己私有变量,都需要基于作用域链的机制向上查找
**/
console.log(a, b, c) // 12, undefined, 14
var b = c = a = 20; // var b = 20; c=20; a = 20
console.log(a, b, c) //20, 20, 20
}
fn(a)
console.log(a, b, c) // 12, 13, 20
//---------
var ary = [12, 23]
function fn(ary) {
console.log(ary) //[12, 23]
ary[0] = 100; //[100, 23]
ary = [100] // [100]
ary[0] = 0 // [0]
console.log(ary) //[0]
}
fn(ary)
console.log(ary) //[100, 23]
var a = 12
function fn() {
// arguments:实参集合,arguments.callee:函数本身fn
console.log(a)
}
function sum() {
var a = 120
fn(); // 12
}
sum();
//-------
var n = 10;
function fn() {
var n = 20;
function f() {
n++;
console.log(n)
}
f()
return f;
}
var x = fn(); //21
x(); //22
x(); //23
console.log(n); // 10
js中的内存分为堆内存和栈内存
堆内存:存储引用数据类型值(对象:键值对 函数: 代码字符串)
栈内存:提供js代码执行的环境和存储基本类型数据
【堆内存释放】
让所引用的堆内存空间地址的变量赋值为null即可(没有变量占用这个堆内存了,浏览器会在空闲的时候把它释放)
【栈内存释放】
一般情况下,当函数执行完成,所形成的私有作用域(栈内存)都会自动释放掉(在栈内存中存储的值也都会释放掉),但是也有特殊不销毁的情况:
如果当前栈内存没有释放,那么之前在栈内存中存储的基本值也不会释放,能够一直保存下来
var i = 1;
function fn(i) {
return function (n) {
console.log(n+ (++i));
}
}
var f = fn(2); //先把fn执行(传递实参2),把fn执行的返回结果(return后面的值)赋值股f
f(3) // 把返回的结果执行 =》 6
fn(5)(6) //12 和上面两个步骤类似,都是把fn执行,都是先把fn执行,把fn执行的返回的结果再执行
fn(7)(8) // 16
f(4) //8
//---------
// 在和其它值进行运算的时候一些区别
// i++ ;自身累加1(先拿原有值进行运算,运算结束后,本身累加)
// i++; 自身累加1 (先自身累加1,拿累加后的结果进行运算)
var k = 1;
console.log(5+(k++), k) // 6, 2
console.log(5+ (++k), k) //7, 2
//--------
闭包:
函数执行形成一个私有的作用域,保护里面的私有变量不受外界的干扰,这种保护机制称之为“闭包”。
市面上的开发者认为的闭包是:形成一个不销毁的私有作用域(私有栈内存)才是闭包。
// 闭包:柯理化函数
function fn() {
return function(){
}}
var f = fn()
//闭包:惰性函数
var utils = (function(){
return {
}
})()
真实项目中为保证js的性能(堆栈内存的性能优化),应该可能减少闭包的使用(不销毁的堆栈内存是耗性能的)
闭包保护功能: