一、作用域链、原型链,
作用域是针对变量的,比如我们创建了一个函数,函数里面又包含了一个函数,那么现在就有三个作用域
全局作用域==>函数1作用域==>函数2作用域
作用域的特点就是,先在自己的变量范围中查找,如果找不到,就会沿着作用域往上找。
如:
var a = 1; function b(){ var a = 2; function c(){ var a = 3; console.log(a); } c(); } b();
最后打印出来的是3,因为执行函数c()的时候它在自己的范围内找到了变量a所以就不会越上继续查找,如果在函数c()中没有找到则会继续向上找,一直会找到全局变量a,这个查找的过程就叫作用域链。
不知道你有没有疑问,函数c为什么可以在函数b中查找变量a,因为函数c是在函数b中创建的,也就是说函数c的作用域包括了函数b的作用域,当然也包括了全局作用域,但是函数b不能向函数c中查找变量,因为作用域只会向上查找。
那么什么是原型链呢?
原型链是针对构造函数的,比如我先创建了一个函数,然后通过一个变量new了这个函数,那么这个被new出来的函数就会继承创建出来的那个函数的属性,然后如果我访问new出来的这个函数的某个属性,但是我并没有在这个new出来的函数中定义这个变量,那么它就会往上(向创建出它的函数中)查找,这个查找的过程就叫做原型链。
Object ==> 构造函数1 ==> 构造函数2
就和css中的继承一样,如果自身没有定义就会继承父元素的样式。
function a(){}; a.prototype.name = "追梦子"; var b = new a(); console.log(b.name); //追梦子
二、预解析
console.log(a); //Uncaught ReferenceError: a is not defined
因为没有定义a所以报错了。
var a = 52; console.log(a); //52
有定义a,并且给a赋值了52所以打印a就是52。
console.log(a); //undefined var a = 52;
虽然有定义a但是打印却在变量a的前面,那为什么不是报错而是打印出来的是undefined?因为在js执行代码之前,js会先获取到所有的变量并且把这些变量放置到js代码的顶部。(简称变量声明提前)
实际上,上面的代码是这样执行的:
var a; console.log(a);
所以代码出来的就是undefined,那你是不是会疑问?我们给赋值给a的52到哪去了。虽然我前面说了js会事先获取所有的变量并且将这些变量放置到顶部,但是变量的赋值并不会事先执行,也就是说,你在哪声明的变量,这个变量的赋值就在哪执行。
var a; console.log(a); //undefined
虽然声明了但没有赋值所有undefined
console.log(a); function a(){ this.user = "追梦子"; }
为什么,可以事先就打印出函数a呢?因为函数的赋值在函数声明的时候就已经赋值了,结合上面我说的变量提前,那是不是就可以理解这句话了?
当然这只是一种情况,还有一种情况,稍后说。
function a(){ this.user = "追梦子"; } console.log(a);
正常
a(); //Uncaught TypeError: a is not a function var a = function(){ console.log(52); }
为什么现在又不行了?因为现在的函数已经赋值给了变量a,现在它的执行过程和变量一样了,我们通常把这种函数赋值给变量的形式叫做函数表达式。
var a = function(){ console.log(52); } a(); //52
正常
if(false){ var a = 1; } console.log(a); //undefined
之所以没有报错而是输出了undefined是因为变量存在预解析的情况,又因为js没有块级作用域,所以最后代码就成了这样
var a; if(false){ a = 1; } console.log(a);
总结:
函数分为:函数声明和函数表达式。
函数声明--
function a(){ alert("追梦子博客"); }
函数表达式--
var a = function(){ alert("追梦子"); }
看似两段相同的语句,它们的执行顺序却截然不同,函数声明时的赋值行为是在函数创建的时候进行的,而函数表达式的赋值行为是在执行这句变量时进行的(因为它已经赋值给了变量所以我这里把它称为变量)。
不管是变量还是函数都会存在变量声明提前。
来看看几题有意思的js例题,加以理解。
var a = 1; function b(){ console.log(a); //undefined var a = 5; } b();
为什么打印的是undefined?
我们先来看看它的解析过程:
var a = 1; function b(){ var a console.log(a); //undefined a = 5; } b();
变量提前,但未赋值,所以是undefined.
我们一起来看看另外一题比较有难度的js面试题:
var a = 1; function b() { a = 120; return; function a() {} } b(); alert(a); //1;
如果你看了上面一题我相信你应该有种不知所措的感觉,这里现在为什么又是1了呢?
我把执行过程的代码写出来我相信你就懂了。
var a = 1;
function b() {
var a;
a = 120;
return;
function a() {}
}
b();
alert(a);
如果你正在js的进阶阶段肯定更闷了,你肯定会想我们不是写return了吗?return后面的代码不是不执行吗?为什么这里却影响了这段代码?
虽然return后面的代码不会被执行,但是在js预解析的时候(变量提升的时候)还是会把return后面的变量提前,所以我们这段代码因为变量提前所以函数里面的变量a就成了局部变量,因为函数外部是访问不了函数内部的变量所以就输出了1。
|
|