前言
JavaScript总结笔记篇仅是记载本人学习过程中的一些总结,为了梳理一下知识点,督促自己不断加强学习。文中有些是源自官网,有些是搜集资料,有些是个人观点,难免存在某些知识点疏漏或者是有错误的地方,如果错误之处,希望看到的小伙伴能及时提个醒,避免误导其他小伙伴,也希望我的总结能帮助到正在学或者是将要学习JavaScript的小伙伴们!大家一起努力,早日成为IT界的大神!
作用域、闭包、立即执行函数
一、作用域
1.作用域
[[scope]]:每个JavaScript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。
[[scope]]指的是我们所说的作用域,其中存储了执行期上下文的集合。
2.作用域链:
[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫作用域链。
3.执行期上下文:
当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的, 所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。
4.查找变量:
从作用域的顶端依此向下查找。
function a () {
function b () {
console.log(cc); //执行会报错,b的scope里找不到c
function c () {
var cc = 123;
}
c();
}
b();
}
a();
/* a defined a.[[scope]] -- > 0 : GO
a doing a.[[scope]] -- > 0 : aAo
1 : GO
b defined b.[[scope]] -- > 0 : aAo
1 : GO
b doing b.[[scope]] --> 0 : bAO
1 : aAo
2 : GO
c defined c.[[scope]] -- > 0 : bAo
1 : aAo
2 : GO
c doing c.[[scope]] --> 0 : cAO
1 : bAo
2 : aAo
3 : GO */
function a () {
function b () {
var bbb = 234;
console.log(aaa);
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo(); // 123
二、闭包
(一)定义
当内部函数保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄露。
(二)作用
1.实现公有变量 函数累加器
function add() {
var count = 0;
function demo() {
count ++;
console.log(count);
}
return demo;
}
var counter = add();
counter();
counter();
2.可以做缓存
function eater() {
var food = "";
var obj = {
eat : function () {
console.log("i am eating " + food );
food = "";
},
push : function (myFood) {
food = myFood;
}
}
return obj;
}
var eater1 = eater();
eater.push("banana");
eater.eat();
3.可以实现封装,属性私有化
4.模块化开发,防止污染全局变量
5.Test
function test () {
var num = 100;
function a () {
num ++;
console.log(num);
}
function b () {
num --;
console.log(num);
}
return [a,b];
}
var myArray = test();
myArray[0](); // 101
myArray[1](); // 100
function Person (name, age, sex) {
var a = 0;
this.name = name;
this.age = age;
this.sex = sex;
function sss () {
a ++;
document.write(a);
}
this.say = sss;
}
var oPerson = new Person();
oPerson.say(); // 1
/*
sss函数体被保存到外部,形成闭包,
拿到Person函数的执行期上下文,所以每次执行a + 1;
*/
oPerson.say(); // 2
var oPerson1 = new Person();
oPerson1.say(); // 1
三、立即执行函数
(一)定义
1.此类函数没有声明,在一次执行过后即释放,适合做初始化工作。
Ps:
只有表达式才能被执行符号执行
能被执行符号执行的表达式,函数名称都会被忽略(undefined)
//执行test,一开始结果为a。再执行为undefined
+function test () {
console.log(‘a’);
}();
(二)形式
1.(function (){
}())–》w3c建议
2.(function (){
})()
function test() {
var arr = [];
for(var i = 0; i < 10; i ++) {
arr[i] = funtion () {
document.write(i + "");
}
}
return arr;
}
var myArr = test();
for(var j = 0; j < 10; j++) {
myArr[j]();
}
//打印结果10个10
解决方法:立即执行函数 非常重要!!!
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]();
}
/*
<ul>
<li>a</li>
<li>a</li>
<li>a</li>
<li>a</li>
</ul>
使用原生js,addEventListener,给每个li元素绑定一个click事件,
并输出他们的顺序。
主要考察,利用立即执行函数解决闭包问题。
*/
function test() {
var liCollections = document.getElementsByTagName("li");
for (var i = 0; i < liCollections.length; i++) {
(function (j) {
liCollections[j].addEventListener("click", function () {
console.log(j);
})
}(i))
}
}
test();