JavaScript经典语录
Js的解析与执行过程:
全局中的解析和执行过程:
一:预处理:创建一个此法环境LE,
扫描JS:1.用声明的方式声明的函数(不是函数表达式),2.用var定义的变量。加到预处理阶段的此法环境中
全局环境中的预处理:预处理创建的词法作用域LE相当于windows
二:命名冲突的处理:
1.处理函数声明有冲突时,会覆盖,处理变量声明有冲突时,会忽略。
2.两者都有时,函数声明的权重高一些,最终结果指向函数声明的引用
三:全局函数的执行
1.首先进行全局预处理
2.执行完预处理后,代码一步步解析
补充:运用词法的作用域,可以很好的解释一个带多个参数的函数只传递一个参数的例子。
函数中的解析和执行过程:
函数中的解析和执行过程区别不是很大,有一个(arguments)注意一下:
1.函数的预处理和全局的预处理类似(只是加了一个arguments,调用函数时实际调用的参数个数)
如果不是var 声明的变量,会变成最外部LE的成员,即全局变量
JS的作用域和作用域链:
作用域一般分为四类:块级作用域、函数作用域、动态作用域、词法作用域(静态作用域)
块级作用域:(js没有块级作用域)
函数作用域:没有纯粹的函数作用域
动态作用域:没有动态作用域
词法作用域(静态作用域)javascript的作用域为静态作用域
f[[scope]]==LE==window
分析:1.创建一个作用域对象f[[scope]]==创建它时的词法环境LE(LE==window)
2.真正执行的时候(一步一步往上找)LE--->f.[[scope]]==window
在词法解析阶段,就已经确定了相关的作用域。作用域还会形成一个相关的链条,称为作用域链
new Function的情况又不一样
问题:
多个函数都想要一个变量,每次都要写一个好麻烦
方法:将变量设置为全局变量
问题:
不是说要减少全局用量的使用么?因为在我们做大项目的时候难免要引入多个JS库,变量间的命名可能会有冲突,且出错后不易查找,这个时候我们该怎么办呢?
方法:将变量设置在一个function中,
问题:
在外面又访问不到了,怎么办?
方法:我们使用匿名函数的方法
Javascript中的作用域链:
当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会创建为其创建一个作用域又称为执行上下文(Execution Context)
在页面加载后会首先创建一个全局的作用域,然后每执行一个函数,会建立一个对应的作用域,从而形成了一条作用域链。
每个作用域都有一条对应的作用域链,链头是全局作用域,链尾是当前函数作用域。
作用域链的作用是用于解析标识符,当函数被创建时(不是执行),
会将this、arguments、命名参数和该函数中的所有局部变量添加到该当前作用域中,
当JavaScript需要查找变量X的时候(这个过程称为变量解析),它首先会从作用域链中的链尾也就是当前作用域进行查找是否有X属性,如果没有找到就顺着作用域链继续查找,直到查找到链头,也就是全局作用域链,仍未找到该变量的话,就认为这段代码的作用域链上不存在x变量,并抛出一个引用错误(ReferenceError)的异常。
1.JavaScript中没有块级作用域,但是有词法作用域
函数内部不用var关键字申明的变量,则默认该变量为全局变量
在javascript中如果不创建变量,直接去使用则报错
2.javascript中如果创建值而不赋值,则该值为unefined
javascript 的函数在被执行之前,会将其中的变量全部申明而不赋值
3.词法作用域是不可逆的
闭包函数的由来:
作用域的存在帮我们省不少事,如果想在函数A中调用函数B该怎么办?
思路:我们给函数B设一个返回值,然后在函数A中调用,代码如下:
function A(){
function B(){
console.log("Hello foodoir!");
}
return B;
}
var c = A();
c();//Hello foodoir!
这样我们就可以得到我们想要的结果。这样,我们基本上到了一个最简单的闭包形式。我们再回过头分析代码:
(1)定义了一个普通函数A
(2)在A中定义了普通函数B
(3)在A中返回B(确切的讲,在A中返回B的引用)
(4)执行A(),把A的返回结果赋值给变量 c
(5)执行 c()
把这5步操作总结成一句话:函数A的内部函数B被函数A外的一个变量 c 引用。当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。
来看下面的几种闭包:demo1:
function fn(){
var b = "foodoir";
return function(){
console.log(b);//foodoir
return b;
}
}
//console.log(b);//b is not defined
var result = fn();
console.log(result());//foodoir
demo2:
var n;
function f(){
var b = "foodoir";
n = function(){
return b;
}
}
f();
console.log(n());//foodoir
demo3:
//相关定义与闭包
function f(arg){
var n = function(){
return arg;
};
arg++;
return n;
}
var m = f(123);
console.log(m());//124
//注意,当我们返回函数被调用时,arg++已经执行过一次递增操作了,所以m()返回的是更新后的值。
demo4:闭包中的读取与修改
//闭包中的设置与修改
var getValue,setValue;
(function(){
var n = 0;
getValue = function(){
return n;
};
setValue = function(x){
n = x;
}
})();
//console.log(n);
console.log(getValue());//0
console.log(setValue());//undefined setValue(123);
console.log(getValue());//123
demo5:用闭包实现迭代效果
//用闭包实现迭代器效果
function test(x){
//得到一个数组内部指针的函数
var i=0;
return function(){
return x[i++];
};
}
var next = test(["a","b","c","d"]);
console.log(next());//a
console.log(next());//b
console.log(next());//c
console.log(next());//d
demo6:循环中的闭包
//循环中的闭包
function fn(){
var a = [];
for(var i=0;i<3;i++){
a[i] = function(){
return i;
}
}
return a;
}
var a = fn();
console.log(a[0]());//3
console.log(a[1]());//3
console.log(a[2]());//3 /*
* 我们这里创建的三个闭包,结果都指向一个共同的局部变量i。
* 但是闭包并不会记录它们的值,它们所拥有的只是一个i的连接,因此只能返回i的当前值。
* 由于循环结束时i的值为3,所以这三个函数都指向了3这一个共同值。
* */
思考:如何使结果输出分别为0、1、2呢?
思路一:我们可以尝试使用自调用函数
function fn(){
var a = [];
for(var i=0;i<3;i++){
a[i] = (function(x){
return function(){
return x;
}
})(i);
}
return a;
}
var a = fn();
console.log(a[0]());//0
console.log(a[1]());//1
console.log(a[2]());//2
思路二:我们将i值本地化
function fa(){
function fb(x){
return function(){
return x;
}
}
var a = [];
for(var i=0;i<3;i++){
a[i] = fb(i)
}
return a;
}
console.log(a[0]());//0
console.log(a[1]());//1
console.log(a[2]());//2
在这里,我们来对闭包进行更深一步的操作
我们再将demo1的例子进行扩展
代码示例如下:
function funcTest(){
var tmpNum=100; //私有变量
//在函数funcTest内
//定义另外的函数作为funcTest的方法函数
function innerFuncTest(
{
alert(tmpNum);
//引用外层函数funcTest的临时变量tmpNum
} return innerFuncTest; //返回内部函数
} //调用函数
var myFuncTest=funcTest();
myFuncTest();//弹出100
到这,我们对闭包的概念和用法有更加熟悉
闭包和this相关
闭包应用举例,模拟类的私有属性,利用闭包的性质,局部变量只有在sayAge方法中才可以访问,而name在外部也访问,从而实现了类的私有属性。
function User(){
this.name = "foodoir"; //共有属性
var age = 21; //私有属性
this.sayAge=function(){
console.log("my age is " + age);
}
}
var user = new User();
console.log(user.name); //"foodoir"
console.log(user.age); //"undefined"
user.sayAge(); //"my age is 21"
关于闭包更深入的了解
(function(document){
var viewport;
var obj = {
init:function(id){
viewport = document.querySelector("#"+id);
},
addChild:function(child){
viewport.appendChild(child);
},
removeChild:function(child){
viewport.removeChild(child);
}
}
window.jView = obj;
})(document);
这个组件的作用是:初始化一个容器,然后可以给这个容器添加子容器,也可以移除一个容器。功能很简单,但这里涉及到了另外一个概念:立即执行函数。 简单了解一下就行。主要是要理解这种写法是怎么实现闭包功能的。
闭包并不是万能的,它也有它的缺点
1、闭包会使得函数中的变量都保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页性能问题。另外在IE下有可能引发内存泄漏 (内存泄漏指当你的页面跳转的时候 内存不会释放 一直占用你的CPU 只有当你关闭了浏览器才会被释放);
2、闭包会在父函数外部改变父函数内部的变量的值,所以不要随便改动父函数内部的值。
JavaScript经典语录的更多相关文章
- ios开发经典语录锦集
原文链接: iPhone开发经典语录集锦 前言:iPhone是个极具艺术性的平台,相信大家在开发过程中一定有很多感触,希望能写出来一起交流,所以开了这个帖子,以后还会维护. 如果大家和我一样有感触的话 ...
- 转载:百度原CTO李一男经典语录
原文地址:http://www.cnblogs.com/marvin/archive/2010/01/20/1652088.html 百度原CTO李一男经典语录 [1]好好规划自己的路,不要跟着感觉走 ...
- JavaScript经典作用域问题(转载)
题目 var a = 10; function test(){ a = 100; console.log(a); console.log(this.a); var a; console.log(a); ...
- 《javascript经典入门》-day02
<javascript经典入门>-day02 1.使用函数 1.1基本语法 function sayHello() { aler('Hello'); //...其他语句... } #关于函 ...
- 《javascript经典入门》-day01
<javascript经典入门>-day01 1.了解JavaScript 01.浏览器每次加载和显示页面时,都在内存里创建页面及其全部元素的一个内部表示体系,,也就是DOM.在DOM里, ...
- JavaScript经典魔力代码
是什么使得JavaScript不同于其他程序设计语言,在浏览器修饰方面表现出其优异的特性?毫无疑问,JavaScript在Web应用领域受到的好评,既源于它自身灵活的动态特性,也源于浏览器对它充分的支 ...
- javascript经典面试题之for循环click
经典重现 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf- ...
- Javascript经典算法学习1:产生随机数组的辅助类
辅助类 在几个经典排序算法学习部分,为方便统一测试不同算法,新建了一个辅助类,主要功能为:产生指定长度的随机数组,提供打印输出数组,交换两个元素等功能,代码如下: function ArraySort ...
- JavaScript --经典问题
JavaScript中如何检测一个变量是一个String类型?请写出函数实现 方法1. function isString(obj){ return typeof(obj) === "str ...
随机推荐
- javascript 函数调用方式
1. 通过函数名直接调用 函数名(实际参数): 2. 通过指向函数的变量去调用 var 变量=函数名: 变量(实际参数):
- hdu 4315 Climbing the Hill(阶梯博弈转nim博弈)
Climbing the Hill Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- 关于gridview 实现查询功能的方法
protected void btnSearch_Click(object sender, EventArgs e) { TestCon(); } protected void btnAllData_ ...
- 高度30px,宽度自适应,点线在文字中间
<style> .div{ position: relative; width: 100%; height: 30px; background: #ffff00} .div ...
- jar转dll
IKVM http://www.cnblogs.com/luckeryin/archive/2012/03/28/2421274.html
- mysql把查询的结果格式成日期
SELECT *,FROM_UNIXTIME(addtime, '%Y-%m-%d %H:%i:%S') as riqi FROM `test`
- OpenLDAP使用疑惑解答及使用Java完成LDAP身份认证
导读 LDAP(轻量级目录访问协议,Lightweight Directory Access Protocol)是实现提供被称为目录服务的信息服务.目录服务是一种特殊的数据库系统,其专门针对读取,浏览 ...
- ExecuteNonQuery()返回值注意点
在使用ExecuteNonQuery(),调用存储过程,语句执行无错误,但是返回结果一直是-1 原因: 当使用储存过程时, 要把SET NOCOUNT ON 这个语句去掉, 这样数据就有反回值了 当 ...
- NSDate的运算
NSDate存储的是世界标准时(UTC),输出时需要根据时区转换为本地时间 Dates NSDate类提供了创建date,比较date以及计算两个date之间间隔的功能.Date对象是不可改变的. 如 ...
- 一张图告诉你为什么 Gmail 是最好的邮箱,以及大量私货
今天早上,我的同事详细介绍了 Gmail 相比其他邮箱的优势,比如强大的垃圾邮件过滤.简单的使用界面.强大的功能设置等等.但是对我来说,这些并不是我使用 Gmail 的最重要原因. 我第一个正式的邮箱 ...