定义:
JavaScript”预解析”,可以理解为把变量或函数预先解析到它们被使用的环境中。
解析过程:
第一步,会预先解析关键字var、function等
第二步,提前赋值:
1. var a = 10 提前解析 var a;(此时a的值为undefined)
2. 函数,在正式运行代码前,赋值为整个函数块
console.log(fn) //function变量提升 function fn(){console.log("123")} function fn(){ console.log("123") }
第三步,预解析结束后,浏览器再逐行解读代码;
//看看下面的代码输出结果 console.log(a) var a = 1; //解析过程 var a; console.log(a); //var变量提升 undefined a = 1;
解析过程:
预解析过程中,当变量和函数同名时:只留下函数的值,不管谁前谁后,所以函数优先级更高;
console.log(fn) //function变量提升 function fn(){console.log("123")}
var fn = 234;
function fn(){
console.log("123")
}
经典预解析面试题
console.log(a)
var a=1;
function a(){console.log(2)}
console.log(a)
var a=3;
console.log(a)
function a(){console.log(4)}
console.log(a)
function fun ( n ) {
console.log( n );
var n = 456;
console.log( n );
}
var n = 123;
fun( n );
答:123 456
//解析过程
//预解析
var n;
function fun(){};
n = 123 //全局变量
fun(n) 当执行fun(n),会执行函数体里的内容,此时fun函数会形成一个新的私有作用域
//fun()内部解析过程
//如果有形参,先给形参赋值
var n = 123;
//进行私有作用域中的预解析;
var n;
//私有作用域中的代码从上到下执行
console.log( n ); //123
n = 456;
console.log( n ); //456
作用域
定义:
它是指对某一变量和方法具有访问权限的代码空间, 在JS中, 作用域是在函数中维护的。
表示变量 或函数起作用的区域,指代了它们在什么样的上下文中执行,亦即上下文执行环境
ES5的作用域只有两种:全局作用域和局部作用域
全局作用域
var a=1; //全局作用域
function fn1(){
console.log(a)
};
fn1()
局部作用域
function fn1(){
var a=1; //局部作用域
};
fn1();
console.log(a);
全局变量和局部变量同名的坑
(1)在全局变量和局部变量不同名时,其作用域是整个程序。
(2)在全局变量和局部变量同名时,全局变量的作用域不包含同名局部变量的作用域。
var a=1;
function fn1(){
console.log(a)
var a = 2;
};
fn1();
console.log(a);
经典作用域面试题
var a = 10;
function f1(){
var b = 2 * a;
var a = 20;
var c = a+1;
console.log(b);
console.log(c);
}
f1()
var a=10;
function test(){
console.log(a);
a=100;
console.log(this.a);
var a;
console.log(a);
}
test();
this指向
this是什么
1. this是Javascript语言的一个关键字。
2. 它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用,随着函数使用场合的不同,this的值会发生变化,指向是不确定的,也就是说是可以动态改变的;
3. 但是有一个总的原则,那就是this指的是,调用函数的那个对象。
this有什么用?平时我们在哪里用到过
<ul>
<li>1111</li>
<li>2222</li>
<li>3333</li>
<li>4444</li>
</ul>
<script type="text/javascript">
$("ul li").click(function() {
$(this).css('color','#f00').siblings().css('color','#333');
})
</script>
// 这个是不是好熟悉,这是我们在用到Jquery时最多的处理方式,这里的this就是当前单击的li;
//这是我们接触到的最简单的this,用途相信很多同学都是理解的,但在实际的应用中this并不只是这么简单,还有其它的引用
1. 在简单函数中的使用
function test(){
console.log(this) //window
};
test()
在这种情况下,因为代码不是运行在严格模式下, this 又必须是一个对象, 所以他的值默认为全局对象。
因为严格模式下,this的值为undefined
function test(){
"use strict"; //严格模式
console.log(this) //undefined
};
test()
2、在对象的方法中使用
var obj = {}
obj.a = 3;
obj.fun = function(){
return this.a; // this表示当前o对象 当前的this.a 等价于 obj.a
};
console.log(obj.fun())
// 还有一些特殊的情况:
// 1)对象中调用外部函数
var a = 1;
function test() {
return this.a;
};
var o = {}
o.a = 3;
o.b = test;
console.log(o.b()) // 结果为3,因为当前test()中的this表示的是o对象
// 2)字面量方式中的this
var o = {
name:'sonia',
bind:function() {
return this.name; // 当前this表示为o对象
}
};
o.bind()
3、在构造函数中使用
所谓构造函数,就是通过这个函数生成一个新对象(object)。
当一个函数作为构造器使用时(通过 new 关键字), 它的 this 值绑定到新创建的那个对象。
如果没使用 new 关键字, 那么他就只是一个普通的函数, this 将指向 window 对象。
function Fun(name,age) {
this.name = name;
this.age = age;
};
var fun = new Fun('lili',22);
console.log(fun.name);
在上面的示例中, 有一个名为 Fun() 的构造函数。通过使用 new 操作符创建了一个全新的对象,名为fun。
同时还通传给构造函数参数, 作为新对象的name、age属性。
通过最后一行代码中可以看到这个字符串成功的打印出来了, 因为 this 指向的是新创建的对象, 而不是构造函数本身。
4、 如何改变this的指向
//apply() 方法接收两个参数: 第一个是要设置为 this 的那个对象, 第二个参数是可选的,如果要传入参数,则封装为数组作为 apply() 的第二个参数即可。
//call() 方法 和 apply() 基本上是一样的, 除了后面的参数不是数组, 而是分散开一个一个地附加在后面。
var num = 10;
function test(){
return this.num;
};
var obj ={
num : 5,
fun:test
}
console.log(obj.fun.call(this)) //返回的值是10,当前的this表示全局对象
var num = 10;
function test(){
return this.num;
};
var obj ={
num : 5,
fun:test
}
console.log(obj.fun.call(obj)) //返回值为5,当前的this为obj对象
常见面试题
var number = 1;
var obj = {
number:2,
showNumber:function(){
this.number = 3;
(function(){
console.log(this.number);
})();
console.log(this.number);
}
};
obj.showNumber();
答案是 1 3
由于showNumber方法的拥有者是obj,所以this.number=3; this 指向的就是 obj 的属性 number。
同理,第二个 console.log 打印的也是属性 number。
为什么第二点说一般情况下this都是指向函数的拥有者,因为有特殊情况。函数自执行就是特殊情况,在函数自执行里,this 指向的是:window。所以第一个 console.log 打印的是 window 的属性number。
所以要加一点: 在函数自执行里,this 指向的是 window 对象。
// 测试题:
var length = 100;
function f1() {
console.log( this.length )
}
var obj = {
x: 10,
f2: function( f1 ){
f1();
arguments[0]();
}
}
obj.f2(f1,1);