作用域、闭包基础
-
[[scope]] --隐式属性域
-
函数创建时生成的一个JS内部的隐式属性。
-
函数存储作用域链的容器,作用域里面的存储的是 AO,GO,
- AO ,函数执行期上下文
- GO,全局的执行期上下文
-
当函数执行完成以后,AO是要销毁的,再次执行这个函数时候AO重新生成一个新的AO,AO是一个即使的存储容器。
-
作用域链就是把,AO,GO形成链式关系从上到下排列起来。
-
每一个函数在被定义的时候就已经包含了GO。
- 生成自己AO一定是排列在作用链最顶端的,把GO挤到下面去。
- a函数执行的时候b函数被定义
- 再被定义的时候我在上级环境之中,所以和a函数执行的时候一样。
- GO只有一个,拿的都是堆函数的地址,指向同一个东西
- 这个时候,b函数被销毁的只是自身的AO作用域现在还在。
- a函数执行完毕后,这个时候b函数整个作用域被销毁,整个函数就不存在了
-
只要函数定义就生成相应的作用域,作用域链,然后GO放进去,被执行前一刻生成自己的AO。
-
结束
闭包
-
这里的test3存的就是test2的引用
-
结束后会销毁自己的AO,test2的AO还有
-
当内部函数被返回到外部并保存,一定会产生闭包,闭包会产生原来的作用域链不释放。
-
闭包其实就是一种现象。
立即执行函数 IIFE - immediately-invoked function expression
- GO的函数不会释放,手动执行函数
- 要满足自动执行,执行完成后立即释放
- 立即执行函数 - 初始化函数
- 执行完毕之后就销毁了
- 立即执行函数是支持返回值,需要一个变量来接收保存。
- 括号里面写函数声明 -- 也变成表达式了
- ()括号包裹起来的,数字,变量,函数都会变成表达式。
(function(){})();
(function(){}());// w3c 建议
(function (a,b){
console.log(a+b);
})(1,3);
// 拿到这个值
var num = (function(a,b){
return a + b;
})(1,2);
// 一定是表达式才能被执行符号执行。
var test2 = function (){
console.log(2);// 可以执行
}();
(function(a,b){
return a + b;
})(1,2);
function test() {
var arr = [];
for (var i = 0; i < 10; i++) {
(function (j) {
arr[i] = function () {
console.log(j);
};
})(i);
}
return arr;
}
var test1 = test();
for (var j = 0; j < 10; j++) {
test1[j]();
}
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</body>
</html>
<script>
var op = document.querySelectorAll("li")
for (var i = 0; i < op.length; i++) {
(function (j) {
op[j].onclick = function () {
console.log(j);
}
})(i);
}
</script>
var fn = (
function test(){
return 1;
},
function test2(){
return "2";
}
)();
// 逗号是运算符,只返回最后一个
console.log(typeof(fn));// string
// 立即执行函数,执行test2函数 ,typeof 返回string
var a = 10;
if(function b(){}){
a += typeof(b);
}
// (function b(){}) 是表达式,忽略b的声明
// 所以只有把一个不存在的值放进typeof(b)的时候才会返回undefined
// 如果直接是 a += b;会报错
console.log(a);// 10undefind
// 累加
function once(){
var num = 0;
return function() {
num = num +1;
console.log(num);
}
}
var test = once();
test();
test();
test();
test();
对象
- 键值对方式书写,逗号隔开 -- 对象字面量
- 使用对象. 属性的方法访问,查找属性方法
- 增加属性方法,对象名.xxx
- 如果改的话直接赋值就行了,方法也可以赋值更改
- 删除使用delete -- delete teacher.name
var teacher = {
name :"张三",
age:32,
sex:"male",
height:176,
weight:130,
teach:function(){
console.log("I am teaching");
},
smoke:function(){
console.log("I am smoke");
}
}
// 查找
console.log(reacher.name);// 张三
teacher.teach();
// 增加
teacher.address = "beijing";
teacher.drink = function (){
console.log("I am drinking beer");
}
// 改
teacher.name = "李四";
teacher.teach = function (){
console.log("I am lisi");
}
// 删除
delete teacher.name;
delete teacher.drink;
var attend = {
student:[],
total:6,
join:function(name){
this.student.push(name);
if(this.total === this.student.length){
console.log(name + "到课,学生已到齐");
}else{
console.log(name + "学生未到齐");
}
},
leave:function(name){
var idx = this.student.indexOf(name);
if(idx !== -1){
this.student.splice(idx, 1);
}
console.log(name + "早退");
console.log(this.student);
},
classover:function(){
this.student = [];
this.student.length = 0;
console.log("已下课");
}
}
attend.join("李四");
attend.join("王五");
attend.join("张1");
attend.join("张2");
attend.join("张3");
attend.join("张7");
attend.leave("李四")
attend.classover();