作用域
每一个对象都有属性和方法
[[scope]]:每个js函数都有一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供js引擎存取[[scope]]就是其中一个。
[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。
作用域链:[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链。
运行期上下文:当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行期上下文,当函数执行完毕,它所有的执行期上下文被销毁。
查找变量:从作用域链的顶端一次向下查找。
在哪个函数查找就在哪个函数的顶端向下查找
function a(){
function b(){
var b = 234;
}
var a = 123;
b();
}
var glob = 100;
a();
a创建的时候[[scope]]中有一个GO 0
a执行的时候[[scope]]产生AO 0 GO 1向下移
b创建的时候直接拥有a的劳动成果
b执行的时候产生一个AO 所以在b里面访问变量的时候先访问b在放我那 AO 0 AO 1 GO 2
function a(){
function b(){
function c(){
}
c();
}
b();
}
a();
a definded a.[[scope]] 0 :GO
a doing a.[[scope]] 0 :AO
1 :GO
b definded b.[[scope]] 0 :AO a
1 :GO
b doing b.[[scope]] 0 :AO b
1 :AO a
2 :GO
c definded c.[[scope]] 0 :AO b
1 :AO a
2 :GO
c doing c.[[scope]] 0 :AO c
1 :AO b
2 :AO a
3 :GO
闭包
function a(){
function b(){
var bbb = 234;
document.write(aaa);
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo();
内部的函数保存到外部必须生成闭包
function a(){
var num = 100;
function b(){
num++;
console.log(num);
}
return b;
}
var demo = a();
demo(); //101
demo(); //102
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露。
闭包的作用
1.实现公有变量
function add(){
var count = 0;
function demo(){
count ++;
console.log(count);
}
return demo;
}
var counter = add();
counter();
counter();
//累加器
function test(){
var num = 100;
function a(){
num++;
console.log(num);
}
function b(){
num--;
console.log(num);
}
return [a,b];
}
var myArr = test();
myArr[0]();//101
myArr[1]();//100
//不依赖外部变量的累加器
function test(){
var num = 0;
function add(){
console.log(++num);
}
return add;
}
var myAdd = test();
test()//---1
test()//---2
2.可以做缓存(存储结构)
function eater(){
var food = "";
var obj = {
eat:funvtion(){
console.log("i am eating"+food);
food = "";
},
push:function(myfood){
food = myFood;
}
}
return obj;
}
var eater1 = eater();
eater1.push("banana");
eater1.eat(); //i am eating banana
3.可以实现封装,属性私有化。
4.模块化开发,防止污染全局变量
立即执行函数
定义:此类型函数没有声明,在一次执行过后即释放。适合做初始化工作。
//立即执行函数
//针对初始化功能的函数
(function (){
var a = 123;
var b = 234;
console.log(a+b);
}());
(function (a,b,c){
console.log(a+b+c);
}(1,2,3));
var num = (function (a,b,c){
return a+b+c;
}(1,2,3));
(function (){}()); w3c建议第一种
(function (){})();
//只有表达式才能被执行符号执行
//函数声明 不是表达式所以不能被执行
function test(){
var a=123;
}
//函数表达式 能执行
var test = function (){
console.log(123);
}();
//一个表达式被执行忽略函数名
function test(a,b,c,d){
console.log(a+b+c+d);
}(1,2,3,4);//不会执行也不会报错
function test(){
var arr = [];
for(var i = 0;i<10;i++){
arr[i] = function(){
document.write(i+"");
//在执行的时候才会执行这一句
//在执行的时候i已经变成10
}
}
return arr;
}
var myArr = test();
for(var j = 0;j<10;j++){
myArr[j]();
}
//10 10 10 10 10 10 10 10 10
//若想输出0,1,2,3.....
function test(){
var arr = [];
for(var i = 0;i<10;i++){
(function(j){
arr[j] = function(){
document.write(j+"");
};
}(i));
}
return arr;
}
var myArr = test();
for(var j = 0;j<10;j++){
myArr[j]();
}
//0 1 2 3 4 5 6 7 8 9
//计算字符串的长度
function reByteslen(target){
var count = 0;
for(var i = 0;i<target.length;i++){
if(target.charCodeAt(i)<=255){
count++;
}else if(target.charCodeAt(i)>255){
count +=2;
}
}
console.log(count);
}
//简化
function reByteslen(target){
var count,
len;
count = len = target.length;
for(var i = 0;i<len;i++){
if(target.charCodeAt(i)>255){
count ++;
}
}
console.log(count);
}
var f = (
function f(){
return "1";
},
function g(){
return 2;
}
)();
typeof f;//number
var x = 1;
if(function f(){}){
x+=typeof f;
}
console.log(x);//1undefined