变量提升
javaScript
程序并不全是从上往下一行一行执行的,在执行的过程中有两个阶段:
- 词法解释(编译阶段)
在程序执行过程的时候,先在整个文件中,查找带var
声明的变量,不带var
的变量是全局变量,全局变量是不会提升的,若有带var
声明的变量或者function声明的函数
就提到该语句的当前作用域的最前面 - 运行阶段(代码从上往下按顺序执行)
a = 'icessun';
var a;
console.log(a); // icessun
------------------------------------------
console.log(a);
var a= 'icessun'; // undefined
对于语句:var a='icessun'
,这执行的时候分两步:
- 声明变量
var a
-----编译阶段(词法解释) - 赋值
a='icessun'
------运行阶段,赋值是在变量当前位置进行赋值
// 函数声明方式
function show(){
console.log('icessun');
}
// 函数表达式
var show =function(){
console.log('icessun');
}
函数声明的时候,在其前面调用和后面调用都可以;函数表达式,在其前面调用是不行的。
因为函数声明会提升到当前作用域的最前面。函数表达式不会这样提升,按照前面的理解:当在函数表达式前面调用show()
,就相当于
var show;
show(); // 相当于是===> undefined () 报错
show = function(){
console.log('icessun');
}
当出现函数声明与变量声明同名的情况,函数声明会被优先提升,变量声明被忽略,函数表达式不会被提升。下面程序的执行结果是icessun
show();
var show;
function show(){ // 函数声明
console.log('icessun');
}
show = function(){ // 函数表达式
console.log('hi');
}
---------------------------------------
解释后,相当于:
function show(){ // 函数声明 提升到当前作用域的最前面 var show;被忽略
console.log('icessun');
}
show(); // 输出 icessun
show = function(){ // 函数表达式
console.log('hi');
}
----------------------------------------
show(); // icessun
var show;
function show(){ // 函数声明
console.log('icessun');
}
show() // icessun
show = function(){ // 函数表达式
console.log('hi');
}
show() // hi
如果出现多个同名函数声明,后面的就会把前面的覆盖:
show(); // icessun1
var show;
function show(){ // 函数声明
console.log('icessun');
}
show = function(){ // 函数表达式
console.log('hi');
}
function show(){ // 函数声明
console.log('icessun1');
}
-----------------------------------
解释后,相当于:
function show(){
console.log('icessun1'); // 后面的把前面的覆盖
}
show();
show = function(){ // 函数表达式
console.log('hi');
}
-----------------------------------
show(); // icessun1
var show;
function show(){ // 函数声明
console.log('icessun');
}
show = function(){ // 函数表达式
console.log('hi');
}
function show(){ // 函数声明
console.log('icessun1');
}
show(); // hi
下面的程序执行报错,提示说show
不是一个函数;这是因为,在预解释的时候,IF里面的函数会进行提升,但是不会提升到IF外面去,而是在IF内部的最前面(当前作用域最前面)。
var a=true;
show();
if(a){
function show(){
console.log(1);
} else{
function show(){
console.log(2);
}
}
}
this
关键字指向
this:上下文,会根据当前执行环境变化而变化
- 单独的
this
,指向的是window
这个全局对象
alert(this); // this----->window
- 全局函数中的
this
,指向的是window
这个全局对象
function show(){
alert(this); // this----->window 调用全局函数,是在全局作用域里面执行,所以执行window
}
show();
- 使用
call / apply
的方式调用函数(程序运行的时候才改变this指向)
function show(){
alert(this); // this----->abc,指向call里面传入的对象
}
show.call('cab');
----------------------------------
特殊情况:
function show(){
alert(this); // this----->window
}
show.call(null); // this----->window
show.call(undefined); // this----->window
---------------------------------
给函数传参数:
function show(a,b){
alert(this+'\n' +'a:' +a+'b:'+b);
}
show.call('icessun',10,20); // 第一个参数传给this,后面是a,在后面是b,如果不对形式参数传递参数,默认是undefined
-----------------------------
apply情况:传递参数的时候,后面的参数使用数组包裹起来
---------------------------------
function show(a,b){
alert(this+'\n' +'a:' +a+'b:'+b);
}
show.apply('icessun',[10,20]); // 第一个参数还是this值,后面数组的值是形式参数值a:10;b:20
- 定时器中的
this
,指向的是window
setTimeout(function(){
alert(this) ;// this----->window
},500)
- 元素绑定事件,事件触发后,执行的函数中的
this
指向的是当前的元素(触发事件的元素)
<input>点我</input>
window.onload=function(){
var oBtn=document.querySelector('input');
oBtn.click=function(){
alert(this);// this指向当前触发事件的元素对象(按钮)
alert(this.value); // 点我
}
}
- 函数调用时,如果绑定了
bind
,那么函数中的this
就指向bind
中绑定的东西(程序未运行的时候,预解释的时候就改变了this指向,就已经确定了this的指向)
var a=10
window.onload = function(){
var oBtn = document.querySelector('input');
oBtn.addEventListener('click',function(){
alert(this); // this------->window
alert(this.a); // 10
}.bind(window)); // 用window替换了事件对象作为里面的this值
}
-对象中的方法:如果该方法被哪个对象调用,那么方法中的this
就指向该对象
var obj={
userName:'icessun',
show:function(){
alert(this.userName); // this----->obj
}
};
obj.show();
-------------------------------
var obj={
userName:'icessun',
show:function(){
alert(this.userName);
}
};
var fn=obj.show; // this------>obj
fn(); // this------>window
- 函数调用的时候,前面加上
new
关键字
function show(){
alert(this); // this----->object 对象 输出undefined
}
new show();
----------------------------------
这个对象是什么?
function show(){
// alert(this); // this----->object 对象
this.userName = 'icessun' // this就是指向的a对象
}
var a=new show();
alert(a.userName);
// 面试题
var x=20;
var a={
x:15,
fn:function(){
var x=30;
return function(){
return this.x;
};
}
};
console.log(a.fn()); // function(){return this.x}
console.log((a.fn())()); // 相当于把返回的函数当作一个表达式,然后执行;也就是说把返回的函数作为一个自执行函数表达式。那么this指向window 返回20
console.log(a.fn()()); // 把返回的函数执行,当作一个闭包,闭包里面的this指向window,返回20
console.log(a.fn()()==(a.fn())()); // true
console.log(a.fn().call(this)); // call里面的this是指向的window,因为这段代码是在全局作用域里面执行;this.x ====>window.x ----> 20
console.log(a.fn().call(a)); // call函数里面把a对象传入,this.x ======>a.x ------>15
网友评论