1.执行上下文
- 范围:一段<script>或者一个函数
- 全局:变量定义、函数声明(一段<script>)
- 函数:变量定义、函数声明、this、arguments(函数)
//变量提升:var a; function fn(name){var age; age=20; console.log(name,age);}
console.log(a);//undefined
var a = 100;
fn('zhangsan');//zhangsan 20
function fn(name){
age = 20;
console.log(name,age);
var age;
}
区分函数声明和函数表达式
- 函数声明:function fn(){}
- 函数表达式:var fn = function(){}
2.this
this要在执行时才能确认值,定义时无法确认。
var a = {
name :'A',
fn : function(){
console.log(this.name);
}
}
a.fn();//this === a
a.fn.call({name:'B'})//this === {name:'B'}
var fn1 = a.fn;
fn1();//this === window
- 作为构造函数执行
- 作为对象属性执行
- 作为普通函数执行
- call apply bind
// 1. 作为构造函数执行
function Foo(name){
this.name = name;//this 是 Foo {name: "zhangsan"}
}
var f = new Foo('zhangsan');
// 2. 作为对象属性执行
var obj = {
name : 'A',
printName : function(){
console.log(this.name);//this 是 {name: "A", printName: ƒ}
}
}
obj.printName();
// 3. 作为普通函数执行
function fn(){
console.log(this);//this === window
}
fn();
// 4. call apply bind
function fn1(name,age){
alert(name);
console.log(this);//{x: 100}
}
fn1.call({x:100},'zhangsan',20);//第一个参数就是this
fn1.apply({x:100},['zhangsan',20]);//区别在于第二个参数
//.bind()必须接在函数表达式后
var fn2 = function(name,age){
alert(name);
console.log(this);//{y: 200}
}.bind({y:200})
fn2('zhangsan',20);
3.作用域
javascript
只有函数作用域和全局作用域,没有块级作用域。
//没有块级作用域
if(true){
var name = 'zhangsan';
}
console.log(name);//zhangsan,此处name有值
//函数作用域和全局作用域(一个script是一个全局范围)
var a = 100;
function fn(){
var a = 200;
console.log('fn',a);//fn 200
}
console.log('global',a);//global 100
fn();
4.作用域链
当前作用域没有定义的变量,叫做自由变量。
如果在当前作用域下没有找到定义的参数,则一级一级向上在父级作用域中查找(函数定义时的作用域中查找)。
//注意区分定义时作用域
function F1(){
var a = 100;
return function(){
console.log(a);//a为自由变量,在父作用域中查找
}
}
var f1 = F1();
var a =200;
f1();//100,注意此处为100而非200
//作用域链
var a = 100;
function fn1(){
var b = 200;
function fn2(){
var c = 300;
//当前作用域没有定义的变量,叫做自由变量
console.log(a);//100,a为自由变量
console.log(b);//200,b为自由变量
console.log(c);//300
}
fn2();
}
fn1();
5.闭包
闭包的使用场景:
- 1.函数作为返回值;
- 2.函数作为参数来传递。
//1.函数作为返回值
function F1(){
var a = 100;
//返回一个函数
return function(){
console.log(a);
}
}
var f1 = F1();
var a =200;
f1();//100
//2.函数作为参数传递
function F1(){
var a = 100;
//返回一个函数
return function(){
console.log(a);
}
}
var f1 = F1();
function F2(fn){
var a = 200;
fn();
}
F2(f1);//100
6.闭包的实际应用
闭包在实际应用中主要用于封装变量,收敛权限。
//函数外部不可访问_list 变量
function isFirstLoad(){
var _list = [];//_表示私有变量
return function(id){
if(_list.indexOf(id) >= 0){
return false;
}else{
_list.push(id);
return true;
}
}
}
var firstLoad = isFirstLoad();
firstLoad(100);//true
firstLoad(100);//false
firstLoad(200);//true
firstLoad(200);//false
7.一个面试题
题目:创建10个<a>
标签,点击的时候弹出来对应的序号?
//错误写法!!!
var i,a;
for(i = 0; i < 10; i++){
a = document.createElement('a');
a.innerHTML = i + '<br>';
a.addEventListener('click',function(e){
e.preventDefault();
alert(i);//此时点击每一个序号弹出来的都是10
});
document.body.appendChild(a);
}
console.log(i);//10
//正确写法
var i;
for(i = 0; i < 10; i++){
(function(i){
var a = document.createElement('a');
a.innerHTML = i + '<br>';
a.addEventListener('click',function(e){
e.preventDefault();
alert(i);
});
document.body.appendChild(a);
})(i);
}
console.log(i);//10
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。