知识点
- 执行上下文
- this
- 作用域
- 作用域链
闭包
执行上下文
- 范围:一段
<script>
或者一个函数 - 全局:变量定义、函数声明
- 函数:变量定义、函数声明、this、arguments
- 范围:一段
12345678910111213141516171819202122 | //全局中或某个函数体中,程序会把变量声明提前,并且用undefined占位(即赋值)//也会把函数声明提前console.log(a);//undefinedvar a = 100; fn('kk');//kk 20function fn(name) { age = 20; console.log(name, age); var age;}//详细运行过程如下// var a;// //函数fn也被提前;// console.log(a);//因为只是声明提前,赋值没有提前,所有undedined// a = 100;// fn('kk');///////////// function fn(name) {// var age;//同理,声明被提前 name也被赋值// console.log(name, age)// } |
123456789 | fn1();//正常执行function () {}//这里fn2声明被提前,还没有赋值,所有报错:undefinedfn2();var fn2 = function() {} |
12345678 | var a = 10;console.log(this.a);//10function fn(name) { var a = 1; console.log(this.a);//this是运行环境的this,而不是定义环境的this console.log(arguments);//函数参数的集合体}fn('kk');//10;["kk",callee:....] |
this 要在执行时才能确认值,定义时无法确认(所以程序中的bug在执行时才会报错,定义时无法发现)
作为构造函数执行
123456
var Foo = function(name) { //this = {} this.name = name; //return this;}var f = new Foo('kk');
作为对象属性执行
1234567
var obj = { name:'A', printName: function() { console.log(this.name); }}obj.printName();
作为普通函数执行
1234
function fn() { console.log(this);}fn();//window
call apply bind
1234567
function fn(name) { this.name = name; console.log(this.name);}fn.call({age:20},'kk');//kkfn.apply({age:20},['kk']);//kkfn();//undefined
1234 | var fn = function() { console.log(this.name);}.bind({name:'kk'})//bind 必须是函数表达式,函数声明是不可以的fn();//kk |
作用域
没有块级作用域
1234
if(true) { var name = "kk";}console.log(name);//kk
只有函数和全局作用域
1234567
var a = 'outer';function fn() { var a = 'inner'; console.log(a);//inner}console.log(a);//outerfn();
作用域链 父级作用域是在定义是决定的,而不是运行时决定
123大专栏 作用域和闭包n>456
var g = 'global'function fn() { //g为'自由变量',即当前作用域没有的变量 console.log(g);//global 从父级中找,当前作用域的父级作用域是全局作用域}fn();
闭包 闭包的使用场景两种
函数作文返回值
12345678910111213
function F1() { var a = 100; return function() { console.log(a); //a是自由变量,所以会从父级寻找值 //又因为函数的父级作用域是定义时决定,而不是运行时决定 //所以父级作用域是F1,a为100 }}var f1 = F1();var a = 200;f1();//100
函数参数传递
1234567891011121314
//函数作为参数到另一个函数里执行function F1() { var a = 100; return function() { console.log(a); }}var f1 = F1();function F2(fn) { var a = 200; fn();}F2(f1);//100
总结
说一下对变量提升的理解
12
变量定义函数声明(注意和函数表达式的区别)
说明this几种不同的使用场景
1
4种看前面
创建10个a标签 点击时候打印出对应的序号
12345678910111213
//错误var i,a;for(i=0;i<10;i++) { a = document.createElement('a'); a.innerHTML = i; a.addEventListener('click', function(e) {//每个i对应一个click共10个 e.preventDefault(); console.log(i);//无论点击哪个结果都是 10 //因为 i 是自由变量,到父级(全局作用域)寻找i的值,而这时循环结束 //i已经是10 }) document.body.appendChild(a);}
123456789101112131415 | //正确var i;for(i=0;i<10;i++) { (function (i){ var a = document.createElement('a'); a.innerHTML = i; a.addEventListener('click', function(e) {//每个i对应一个click共10个 e.preventDefault(); console.log(i); //i是自由变量,从父级(自执行函数)中找值,由于i作为参数传递 //所以从参数中取i的值,分别是0~9 }) document.body.appendChild(a); })(i);} |
如何理解作用域
123
自由变量作用域链闭包的两个场景
实际开发中闭包的应用
12345678910111213141516
//闭包实际应用中主要用于封装变量,收敛权限function isFirstLoad() { var _list = []; return function(id) { if(_list.indexOf(id)>=0){ return false; }else{ _list.push(id) return true; } }}var firstLoad = isFirstLoad();console.log(firstLoad(10));//trueconsole.log(firstLoad(10));//false
来源:https://www.cnblogs.com/liuzhongrong/p/12251126.html