JavaScript中作用域和预解析

作用域以及预解析

在javascript中作用域是非常重要的,本文章将会说明作用域以及我们在工作,以及面试中的一些面试题,如果有不足的地方希望大家可以评论指出来,自己一定会及时的改正错误,避免大家走入一些误区。

谈及作用域先就必须要说明预解析和词法作用域。

下面我们先说明一下:

预解析

代码在正常执行操作之前会对文档进行一次解析,这个操作就是将声明提升,

声明包括全局范围内 1.带有var的变量, 2.函数

文档预解析后会把文档中在全局函数中的内容储存起来,将全局中带有var的变量(var和变量名,注意:变量体不会随着提升,加载var只是告诉我们在文档中有一个全局变量是fn,并不会有其他的作用)提升到最前面

预解析后会正常的读取代码(由上至下由左到右)

下面举例说明一下预解析:

var fn=456;

function fn(){

}

在上述的代码中我们预解析后会变成:

var fn;

function fn(){

}

fn=456;

所以不管function是在前面还是后面我们打印fn出来的结果都是456。

词法作用域

词法作用域在书写代码的时候就已经决定了,与运行无关

可以分割词法作用域的只是函数,别的不可以分割

下面举例说明一下词法作用域

if(true){

function fn(){

alert("true");

}

}else{

function fn(){

alert("false");

}

}

fn();

语句在预解析后,会得到以下结果

function fn(){

alert("true");

}

function fn(){

alert("false");

}

if(true){

}

else{

}

fn();

再逐行进行解析;所以上面的函数会被下面的函数覆盖(函数内部的内容会被保存);

在函数执行时会进入判断语句为true的语句中,但是这个时候fn这个函数在预解析后已经变成了false,所以这个时候打印出来的应该是false。

注意:

全局中的函数在预解析之后内容会被保存,在执行时不会被二次解析,会被直接拿来用

上述例子我们写代码中不可能出现,因为函数不能被语句进行包裹,上面只是为了给大家进行演示而做的例子

正式进入主题介绍作用域

不被函数包裹的带有var的变量他们的存在于作用域链的零级链中

被函数包裹的带有var变量他们是存在于作用域中的一级链中

构造函数原型属性(prototype)等是存在于作用域中的二级链中 ,

以此类推,函数一直包裹那么,作用域链也会一直递增下去

在此中要特别注意的是隐式全局变量,隐式全局变量如果在函数内部只有在函数在执行时才会被调用?

下面通过一个复杂的面试题来为大家讲解作用域链:

function Foo(){

getName = function(){

console.log(1);

};

return this;

}

Foo.getName = function(){ console.log(2); };

Foo.prototype.getName = function(){ console.log(3); };

var getName = function(){ console.log(4); };

function getName(){ console.log(5); }

Foo.getName();

getName();

Foo().getName();

getName();

new Foo.getName();

new Foo().getName();

new new Foo().getName();

第一步当文档加载的时候会进行预解析,将声明和带有var的全局变量名提升,

解析完之后零级链上回出现两个函数foo和getname

第二步会由上往下加载给foo函数添加一个名为getname的函数给foo的原型中添加一个getname;在刚才的预解析中,零级链上有一个getname,加载之后出现另一个getname会把之前加载的getname覆盖掉

第三步进入函数的执行,

函数在执行时如果在原来的作用域链中有这个函数时,不用从新二次加载,如果出现同名会直接拿来用,

foo.getname在刚才已经定义了,所以第一个直接得到的是2;

getname在刚才的作用域零级链中已经被从新定义覆盖,所以第二个直接得到的是4;

会先执行foo函数,但是在foo的函数中存在了一个隐式的全局变量(getmame函数);所以当foo执行时会将这个全局变量函数释放出来,getname覆盖原来零级链上的getname;最后执行return this,这个时候this指向的是window,所以会这句话翻译过来也就是window.getname;全局变量中的getname得到的是刚才foo释放出来的隐式全局变量。所以第三个得到的是1;

getname和刚才第三个翻译过来的结果是一样的,只不过是将window省略; 所以第四个的结果同样是1;

new foo.getname, foo不是一个函数,所以不能被new,会先执行后面的Foo.getname;foo.getname和第一个一样;第五个所以得到的是2;最后执行new随后foo.getname变成了一个空对象

new foo().getname() foo是一个函数;new之后就是指被构造函数实例化的对象,对象.getname,但是现在foo这个函数中没有this.getname;所以直接沿着Foo的原型链忘上找;得到了存在于原型链中foo.prototype.getname所以第五个得到的数值是3;

第七个和第六个一样,会执行后面的new Foo().getname;得到一个结果是3;随后把这个函数new了一下,变成了一个空的对象

所以得到的结果是2,4,1,1,2,3,3

注意:

原文地址:https://www.cnblogs.com/tongguilin/p/12229692.html

时间: 2024-08-13 17:53:25

JavaScript中作用域和预解析的相关文章

JavaScript有关作用域和预解析

作用域:使用范围 全局变量:声明的变量是使用var声明的,那么这个变量就是全局变量,全局变量可以在页面的任何位置使用 除了函数以外,其他的任何位置定义的变量都是全局变量 局部变量:在函数内部定义的变量,是局部变量,外面不能使用 全局变量,如果页面不关闭,那么就不会释放,就会占空间,消耗内存 全局作用域:全局变量的使用范围 局部作用域:局部变量的使用范围 块级作用域:一对大括号就可以看成是一块,在这块区域中定义的变量,只能在这个区域中使用,但是在js中在这个块级作用域中定义的变量,外面也能使用;

关于作用域和预解析的不常见重要知识

作用域和预解析 在javascript中作用域是非常重要的,本文章将会说明作用域,如果有不足的地方希望大家可以评论指出来,自己一定会及时的改正错误,避免大家走入一些误区. 谈及作用域先就必须要说明预解析和词法作用域. 下面我们先说明一下: 预解析 代码在正常执行操作之前会对文档进行一次解析,这个操作就是将声明提升, 声明包括全局范围内  1.带有var的变量, 2.函数 文档预解析后会把文档中在全局函数中的内容储存起来,将全局中带有var的变量(var和变量名,注意:变量体不会随着提升,加载va

小白学js第六天之代码规范,作用域以及预解析

目录 代码规范 命名规范 变量规范 注释规范 空格规范 换行规范 作用域 全局变量 局部变量 块级作用域 作用域链 预解析 什么是预解析 变量提升 此篇木有脑图,嘻嘻 代码规范 命名规范 变量.函数的命名必须要有意义 变量一般用名词 函数一般用动词 变量规范 操作符前后要有空格 var name = 'zs'; 注释规范 // 这里是注释 空格规范 if (true) { } for(var i = 0; i < n; i++ ) { } 换行规范 var arr = [1, 2, 3, 4];

javascript中函数的不同解析

<html> <head> <title>javascript的函数的生命周期</title> <meta charset="utf-8"/> <script type="text/javascript"> /* javascript是所有语言中对函数生命周期处理最为复杂的语言之一 而javascript的函数的生命周期取决于js解释器是如何解释我们编写 的js代码,我们以例子来说明javasc

javascript里面的闭包,作用域,预解析

函数的作用域 1.全局变量=公用卫生间 2.局部变量=次卧卫生间      局部变量 全局无法使用      局部声明变量不加var的话就变成全局变量(不推荐使用) 3.闭包=次卧的可以用自己的卫生间,也可以用公用卫生间: 预解析 1.先把变量声明 全部提前,赋值不动 2.函数也有预解析,直接提前   3.预解析 不会脱离函数作用域,也不会冲出script标签 最多提到自己标签的顶部 代码执行顺序 见一个srcipt解析执行一个,执行完了 在执行下一个 案例1:      alert(a);  

JavaScript中---作用域

作用域: 变量还有函数作用的范围. 浏览器的内核主要有两大功能,一个是渲染页面,另一个就是我们的JavaScript的解释器了. 我们主要来说说JavaScript解释器,在解析时是怎么样的工作原理. 在解析的时候,首先会发生预解析,就是说不会直接一行一行去执行我们所写的代码,它会先去找有哪些声明的变量,遇见函数体的时候会把函数放到最上面的位置,当变量名和函数名重名的时候函数会替代变量声明. 在解析的时候碰到的是个函数体,那么会预先处理函数体中的变量或者函数,知道有哪些声明的事项. 如果是变量,

作用域,预解析,对象,内置方法 Math Date Array

作用域 一段程序代码中所用到的名字并不总是有效可用的,而限定这个名字(变量)的可用性的代码范围,就是这个名字的作用域,作用域提高了逻辑程序的局部性,增强了可靠性,减少了名字冲突: JavaScript作用域(es6)之前:全局作用域,局部作用域 全局作用域:整个script标签或者是一个单独的JS文件 局部作用域(函数作用域):在函数内部就是作用域: 变量作用域 全局变量:在全局作用域下声明的变量:如果在函数内部没有声明(var)直接赋值的变量也是全局变量 num = 2; 局部变量:在函数内部

JavaScript中作用域链和闭包

一.匿名函数 1.1 匿名函数的概念 ? 声明一个没有函数名的函数,就是匿名函数. ? 有函数名的函数就是具名函数. 看下面的代码: <script type="text/javascript"> /* //这里定义了一个函数,而且没有函数名.这样写语法是错误的,如果允许这样定义,那么根本就没有办法调用. //所以,我们可以用一个变量来存储一下 function(){ } */ // 声明了一个匿名函数,并把匿名函数赋值给变量f. 注意这个时候这个匿名函数并没有执行. va

JS的作用域和预解析

当我们使用Js 来编写一个函数的时候,总是会分不清,自己所声明的变量到底是全局变量,还是局部变量,这就牵扯到了作用域的问题.以及在函数执行的时候,函数内部的变量与全局变量及输出结果,在不同状况下的关系问题.下面就让我来举例说明一下. 作用域: 指的是代码对不同的“范围”的划分. 划分规则: 1 全局是一个作用域 这个作用域叫做全局作用域 2 只有函数,可以划分这么一个“范围”(作用域) 这样划分出来的作用域叫做私有作用域. 划分规则的应用对象: 变量 所以我们可以理解为: 作用域 划分了一个所有