安邦的JavaScript学习笔记
JavaScript 学习笔记;JavaScript学习总结;前端变化太快,只有把JS基础打扎实了,才能游刃有余;为了让我的JavaScript基础异常牢固,思路更加清晰,我会把以前总结过的知识和平时看到的资料放在这里,把以前零零散散的知
安邦的JavaScript学习笔记
这是当初学习JS时候的笔记,
因小伙伴反应Github不适合阅读,
我在我的个人网站(阿西河前端教程)上也有整理一份,详情参见;
朱安邦的JavaScript学习笔记 (我的个人网站)
后期主要更新在我的个人网站上,感觉我整理后的还是很适合学习和阅读的,服务器放在国内,访问速度也超级快;
然后每年的年底统一把新增的内容更新到当前的Github仓库;
欢迎大家关注我的小网站: https://www.axihe.com/
同时我也在Bilibili上开频道做UP主;欢迎在B站关注我: https://space.bilibili.com/59312814
基于ES5,包含ES6的,笔记最近正在重新整理,有些链接可能失效;会尽快整理好;
- [编辑器的选择/开发环境介绍](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#one)
- [HTML文档和标签介绍](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#two)
- [JS由哪些部分组成、DOM初识](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#three)
- [HTML中怎么使用JS/CSS](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#four)
- [从noscript标签引深出的两种编程思想(优雅降低,渐进增强)](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#five)
- [javascript的文档模式和ES6](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#six)
- [变量的定义和储存值的类型判断](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#seven)
- [强类型语言和弱类型语言的区别](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#eight)
- [编程语言是做什么的?面向对象编程的真正意义是什么?](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#nine)
- [练习题](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#ten)
- [前端技术方向的选择,编程语言是做什么的?](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#eleven)
- [JS代码检测的一些小方法](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/前端开发初识/README.MD#twelve)
- [String](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#one)
- [Number](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#two)
- [Boolean](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#three)
- [null和undefined](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#four) (数据类型详解的时候不再总结,已经写的差不多了)
- [Object](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#five)
- [null和undefined的区别和联系](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#six)
- [Symbol](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#footer)
- [练习题](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#footer)
- [初识函数](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#one)
- [函数的定义](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#two)
- [函数的调用](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#three)
- [函数的方法](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#four)
- [arguments对象](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#five)
- [函数的参数](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#six)
- [this关键字的指向](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/数据类型初识/README.MD#seven)
- [变量的命名](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/变量声明和原理/README.MD#one)
- [变量的声明](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/变量声明和原理/README.MD#two)
- [变量的类型](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/变量声明和原理/README.MD#three)
- [全局变量和局部变量](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/变量声明和原理/README.MD#four)
- [注释和语法建议](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/变量声明和原理/README.MD#five)
- [练习题](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/变量声明和原理/README.MD#footer)
- [算术运算符](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#one)
- [自增与自减](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#two)
- [关系运算符](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#three)
- [对象运算符](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#four)
- [逻辑运算符](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#five)
- [位运算符](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#six)
- [其他运算符](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#seven)
- [=/==/===、!与!!的区别](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#eight)
- [计算器案例](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#nine)
- [表格排序案例](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#ten)
- [练习题](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/表达式和运算符/README.MD#footer)
- [循环语句](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/语句/README.md#one)
- [跳转语句](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/语句/README.md#two)
- [选择语句](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/语句/README.md#three)
- [异常处理语句](https://raw.githubusercontent.com/anbang/javascript-notes/HEAD/语句/README.md#four)
- JS算法原理
- 模块化开发
- 错误处理和异常调试
- 错误处理
- chrome的开发者工具用法
- DOM详细总结
- 事件的原理解析和应用
- 事件流
- 事件对象
- 事件类型
- 完美解决事件的兼容性
- 内存和性能
- 1、事件基础
- 2、基础事件库和拖拽
- 3、事件和观察者模式
- 封装的事件库
- 放大镜
- 表单脚本
- 基础知识
- 文本和选择框
- 表单序列化
- 富文本编辑
- AJAX
- 服务器/浏览器编程的机制和原理,同步和异步交互
- 基于nodeJs环境,用原生JS操作表单
- jsonp跨域ajax,jQuery的AJAX原理和应用
- 编写可维护的javascript代码,性能优化与部署
预解释的原理
预解释的原理
- 预解释的不同机制
- var的预解释机制
- function的预解释机制
- 预解释机制
- in的用法
- 面试题练习
预解释的的不同机制
预解释也叫预声明,是提前解释声明的意思;预解释是针对变量和函数来说的;但是变量和function的的预解释是两套不同的机制;
- 当浏览器加载我们的HTML页面的时候,首先会提供一个供JS代码执行的环境->全局作用域global(浏览器中的全局作用域,也叫顶级作用域是window)
- JS中的内存空间分为两种:栈内存、堆内存
- 栈内存;提供JS代码执行的环境,存储基本数据类型的值;->全局作用域或者私有的作用域其实都是栈内存;
- 堆内存;存储引用数据类型的值(对象是把属性名和属性值储存进去,函数是把函数体内的代码当做字符串储存进去)
- 在当前的作用域中,JS代码执行之前,浏览器首先会默认的把所有代var和function的进行提前的声明或者定义,->"预解释"(也叫变量提升)
var的预解释机制
var a=1
- 1、代码运行之前,先扫描有没有带var关键字的变量名,有的话,为这个变量名,在内存里开一个空间;这时候变量名a是不代表任何值的;用undefined来表示;undefined是一个标识符/记号,表示找不到这个变量名所代表的数据;不存在的意思;这个阶段叫变量的声明;
- 2、当代码运行的时候,则给数据1开辟一个内存空间;
- 3、让数据1和变量名a绑定在一起;变量类型指的就是数据类型;按照js语言的原理来说变量类型有undefined类型;但是数据类型是没有undefined这种数据类型的;只有"undecided"这种字符串类型(字符串类型是数据类型的一种);同理也没有unll这个数据类型,但是有"null"这种字符串类型;
var num;
//1、声明(declare):var num; ->告诉浏览器在当前作用域中有一个num的变量了,如果一个变量只是声明了但是没有赋值,默认的值是undefined
console.log(num);//->undefined
num = 12;
//2、定义(defined):num=12; ->给我们的变量进行赋值
console.log(num);//->12
//变量提前使用的话,就是undefined
console.log(testStr);//undefined
var testStr="22222222"
function关键字的预解释步骤
function fn(){……}
在代码执行之前,把所有的带function关键字的脚本都扫描一遍,然后定义变量;并且同时给变量赋值;
- 1、函数的定义只是保存一些字符串;预解释的时候在内存里保存fn大括号里面的字符串;
- 2、代码运行时候,读到fn()时候,这个时候就是函数的运行;函数的运行,会先开辟一个堆内存把字符串当做代码在堆内存中再次运行,函数产生的作用域内还会再进行预解释和代码运行;函数如果多次执行;会产生多个作用域;但是产生的多个作用域里面的内容都是相互独立的;互相没有关系;(在原型和原型链时候再仔细研究原理;)
fn(100,200);//->可以在上面执行,因为预解释的时候声明+定义就已经完成了
function fn(num1, num2) {
var total = num1 + num2;
console.log(total);
}
总结
- 1、var和function关键字的在预解释的时候操作还是不一样的
- var -> 在预解释的时候只是提前的声明了这个变量,只有当代码执行的时候才会完成赋值操作
- function -> 在预解释的时候会提前的把声明加定义都完成了(在代码执行的时候遇到定义的代码直接的跳过)
- 2、预解释只发生在当前的作用域下,例如:开始只对window下的进行预解释,只有函数执行的时候才会对函数中的进行预解释;
[重要]刚开始只对window下的进行预解释,fn函数中目前存储的都是字符串,所以var total没啥实际的意义,所以不进行预解释 -> "预解释是发生在当前作用域下的"
综合题;
console.log(obj);//->undefined
var obj = {name: "朱安邦", age: 25};
function fn(num1, num2) {//代码执行到这一行的时候直接的跳过这一块的代码,因为在预解释的时候我们已经完成了声明加定义
var total = num1 + num2;
console.log(total);
}
var num1 = 12;
fn(num1, 100);//执行fn,把全局变量num1的值赋值给形参num1,把100赋值给形参num2
- 下面是一个预解释思路
var a,
b = 0,
fn = function () {
var a = b = 2;
};
fn();
console.log(a, b);
把上面解析成下面就好理解了
var a;
window.b = 0;
window.fn = function () {
//var a = b = 2;
var a = 2;//a是私有的和全局没关系
b = 2;//b是全局的
};
fn();//window.fn()
console.log(a, b);//undefined 2
预解释机制
- 1、不管条件是否成立都要进行预解释
console.log(a);//->undefined
if (!!("a" in window)) {//"a" in window -> true
var a = "朱安邦";
}
console.log(a);//->朱安邦
> 例子中的if是不成立的,预解释的时候,碰到非functon内的var,都会声明,无论你写在if else 还是别的判断里;结舌if
> 假设if语句起作用的话,那么第一次log a的时候,就会报错了(没有声明的变量,是不能直接用的,除非typeof),而声明并且没有赋值的表现才是undefined;假设不成立;
> 最开始总结的预解释步骤:**代码运行之前,先扫描有没有带var关键字的变量名,有的话,为这个变量名,在内存里开一个空间;**,预解释是发生在代码执行前的,所以if根本阻挡不了预解释;
- 2、预解释只发生在"="的左边,只把左边的进行预解释,右边的是值是不进行预解释的
匿名函数之函数表达式:把函数定义的部分当做值赋值给一个变量或者元素的事件
fn1();//->undefined() Uncaught TypeError: fn is not a function JS中只有函数可以执行 && JS上面的代码如果报错了,在不进行任何的特殊处理情况下我们下面的代码都不在执行了
var fn1 = function () {
console.log("ok");
};
fn1();
//预解释的时候:fn=xxxfff000
fn2();//->"ok"
function fn2() {
console.log("ok");
}
fn2();//->"ok"
预解释的时候:var fn; ->fn的默认值是undefined;这里即使有functon,也是不能进行进行预解释的
- 3、函数体中return下面的代码都不在执行了,但是下面的代码需要参加预解释;而return后面的东西是需要处理的,但是由于它是当做一个值返回的,所以不进行预解释;
var total = 300;
function fn() {
console.log(total);
return function sum() {};//return是把函数中的值返回到函数的外面,这里是把function对应的内存地址返回的到函数的外面,例如:return xxxfff111;函数体中return下面的代码都不在执行了
var total = 10;
console.log(total);
}
fn();// undefined
- 4、匿名函数的function在全局作用域下是不进行预解释的;
匿名函数之自执行函数:定义和执行一起完成了;函数内的声明,只是在函数内使用;
(function(num){
var testStr="test"+num;
console.log(num);
})(100);
console.log(testStr);// testStr is not defined
- 5、在预解释的时候,如果遇到名字重复了,只声明一次,不重复的声明,但是赋值还是要重复的进行的
预解释:
var fn; 声明
fn = xxxfff000; [声明]不要了+定义
fn = xxxfff111; [声明]不要了+定义
->fn=xxxfff111
var fn = 12;//window.fn=12
function fn() {//window.fn=function(){}
}
function fn() {
}
window下的预解释:
fn=xxxfff111; 声明+定义
var fn; 声明 (这一步不需要处理)
fn=xxxfff222; 声明+定义(只需要执行定义即可)
->fn=xxxfff222
一个案例;
fn();//->2
function fn() {
console.log(1);
}
fn();//->2
var fn = 13;//var fn;跳过 fn=13(在预解释的时候没有执行这句话赋值的操作)
fn();//->13() Error:fn is not a function
function fn() {
console.log(2);
}
fn();
JS中作用域只有两种:
- window全局作用域、
- 函数执行形成的私有作用域;
- {name:""} if(){} for(){} while(){} switch(){} 这些都不会产生作用域;
ES6可以用let形成块级作用域;http://www.cnblogs.com/snandy/archive/2015/05/10/4485832.html
【in】:检测某一个属性名是否属于这个对象(不管是私有的属性还是公有的属性,只要是当前对象的属性返回true,不是的话返回false)
var obj = {name: "王小波", age: 30}; console.log("name" in obj);//->true console.log("height" in obj);//->false
面试题练习
1.写出代码运行的结果;并且把代码运行的步骤写出来;为什么得到所写的结果?
var num = 20;
var obj = {
num: 30,
fn: (function (num) {
this.num *= 3;
num += 15;
var num = 45;
return function () {
this.num *= 4;
num += 20;
console.log(num);
}
})(num)//->把全局变量num的值20赋值给了自执行函数的形参,而不是obj下的30,如果想是obj下的30,我们需要写obj.num
};
var fn = obj.fn;
fn();//->65
obj.fn();//->85
console.log(window.num, obj.num);//->240、120
2.写出代码运行步骤
function fo(){
var i=0;
return function (n) {
return n+i++;
}
};
var f=fo();
var a=f(15);
var b=fo()(15);
var c=fo()(20);
var d=f(20);
console.log(a,b,c,d);//15 15 20 21
- 写出输出的结果
var ary = [1,2,3,4];
function fn(ary){
ary[0] = 0;
ary = [0];
ary[0] = 100;
return ary;
}
var res = fn(ary);
console.log(ary);
console.log(res);
解析步骤如下;
var ary = [1,2,3,4];
function fn(ary){
ary[0] = 0;//ary=[0,2,3,4] 这个时候修改了变量ary[0]了;ary[0] = 0;这个没有重写变量ary;参数ary只是代表了变量ary,保存的还是变量ary的地址;参数ary[0]指向的还是变量ary[0],也就是1,只是把1改为了0;
ary = [0];//ary=[0],这里是重写参数ary了,等号右边的数据[0]保存在fn执行时候产生的堆内存中,参数ary指向的地址,由原来的变量ary地址,重写指向到数据[0]的保存地址,此时的参数ary已经与原来ary无关系了;两者保存的分别是不同的内存地址;
ary[0] = 100;//ary=[100]
return ary;//[100]
}
var res = fn(ary);
console.log(ary);// [0,2,3,4]
console.log(res);//[100]
图解原理如下;

作用域和闭包
作用域和闭包
ECMAScript5;js的代码没有代码块;使用函数运行的机制进行创建闭包;闭包就是作用域的意思;ES5中,JS中只有函数才可以创建能操作的作用域;
JavaScript中的内存也分为栈内存和堆内存。一般来说,栈内存中存放的是存储对象的地址,而堆内存中存放的是存储对象的具体内容。对于原始类型的值而言,其地址和具体内容都存在与栈内存中;而基于引用类型的值,其地址存在栈内存,其具体内容存在堆内存中。堆内存与栈内存是有区别的,栈内存运行效率比堆内存高,空间相对推内存来说较小,反之则是堆内存的特点。所以将构造简单的原始类型值放在栈内存中,将构造复杂的引用类型值放在堆中而不影响栈的效率。
- 函数执行时形成私有作用域
- 全局变量和私有变量
- 如何区分函数中出现的变量是私有的还是非私有的
- 如何查找当前作用域的上级作用域?
- JavaScript中的顶级作用域是谁?
- 变量和属性有什么关系
- 函数运行产生的作用域
- 闭包
- 作用域不销毁的情况|内存释放
函数执行时形成私有作用域
函数执行的时候(直接目的:让函数体中的代码执行)会形成一个新的私有的作用域(栈内存),供函数体中的代码执行;
- 1)给形参赋值
- 2)私有作用域下的预解释
- 3)私有作用域下的代码执行
形成的新的私有的作用域还保护了里面的私有变量不受外界的影响,我们把函数的这种保护机制叫"闭包":为什么要有作用域;因为变量要规定活动范围的,为便于管理不同范围的变量;所以要给变量设置活动范围;
预解释也是在各自的作用域里进行预解释的;
function fn(){
var a=1;
}
fn();
fn();
console.log(a);//Uncaught ReferenceError: a is not defined;
因为a没有声明和定义过,所以报错了;
上面的fn运行了两次,所以产生了两个堆内存;两个作用域(作用域也就是闭包)各自分别有一个a的变量;a的值都是数字1,但是两个变量是不相等的;两个a之间是没有任何关系的;
就好比我们都属于人类;我们都继承了人类这个对象所具有的特征;我有一双手,你也有一双手,但是我们两个人的手是没有关系的;我的手不等于你的手;
全局变量和私有变量
- 在全局作用域下声明的变量是全局变量;
- 在私有作用域中声明的变量是私有变量;函数的形参也是私有的变量;
如何区分函数中出现的变量是私有的还是非私有的?
首先看是否为形参,然后看是否在私有作用域中声明过(有没有var过),两者有其一就是私有的变量,那么在当前函数中不管什么位置出现都是私有的,和全局的没有半毛钱的关系;如果两者都没有,说明不是私有的;如果一个函数中出现的变量不是私有的,那么会往其上级作用域查找,上级没有则继续查找,一直找到window为止,如果window也没有呢?
如果是获取:会报错
function fn() {
console.log(num);//Uncaught ReferenceError: num is not defined
}
fn();
如果是设置:不是私有的,找全局,全局没有的话相当于给全局加一个
function fn() {
num = 13;//相当于给window增加了一个叫做num的属性名,属性值是13 window.num=13;
}
fn();
console.log(num);//13
如何查找当前作用域的上级作用域?
当前作用域的上级作用域是谁和函数在哪执行的没有任何的关系,我们只需要看当前函数是在哪个作用域下定义的,那么它的上级作用域就是谁;
下面是查找上一级作用域,一直找到window的案例;
var total = 100;
function fn() {
var total = 10;
return function () {
console.log(total);
}//如果返回的是一个引用数据类型的值(对象、数组、函数...),首先是把这个值开辟一个内存空间,有一个地址,然后把内存地址返回 ->例如在这里其实返回的就是 return xxxfff111;
}
var f = fn();//f=xxxfff111;
f();
//输出的结果是 10 还是 100 ? 为什么 ?
如果是在自执行函数里呢?
var total = 100;
function fn() {
var total = 10;
return function () {
console.log(total);
}
}
var f = fn();//f=xxxfff111;
~function () {
var total = 1200;
f();//->;里面变量的上级作用域是谁
}();
下面代码输出的是什么?
var a=0;
var b="0";
function fn(){
console.log(a);
console.log(b);
console.log(typeof a);
console.log(typeof b);
a="1";
var b=1;
console.log(a);
console.log(b);
console.log(typeof a);
console.log(typeof b);
}
fn();//运行后会输出什么?如果没有这行代码;函数fn的定义是没有意义的;函数只声明定义,而不运行是没有任何意义的;
//0,undefined,"number","undefined","1",1,"string","number"
预解释是作用域中的预解释;js里是可以函数里面套函数的;都运行的时候,是在函数创建的作用域里再创建一个作用域;
下面是作用域的范围;
var a="window";
console.log(a);//window
function father(){
console.log(a);//undefined
var a="father";
console.log(a);//father
function children(){
console.log(b);//undefined
console.log(a);//father
var b="flag";
a="children";
console.log(a);//children
}
children();
console.log(a);//children
}
father();
console.log(a);//window
JavaScript中的代码执行顺序是从上到下逐条运行的;遇到function定义函数的代码块;直接跳过;遇到函数执行的代码;就找到引用的函数地址;开始跳到执行函数产生的作用域中执行代码;等函数执行完以后,再回到当前作用域执行下面的代码;

上面的代码运行后,输出的是
"window",undefined,"father",undefined,"father","children","children","window"
作用域链查找:当作用域套作用域的时候,children内找不到某个变量;会到children的父作用域father中找;当father中找不到的时候;会到father的父作用域找;一直找到window这个根作用域;属于作用域链式查找;
JavaScript中不带var声明变量,变量会冒泡到上一级作用域中;也就是说会污染到上一级作用域;但是对上上级的作用域是没有影响的;很多教材和视频上说不带var声明的变量;变量会变成全局变量,这个说法是不全面的;
【带var和不带var的区别和关系】
只有在全局作用域下才有这样的关系
区别:带var的可以在代码执行前进行声明,而不带var的不能提前的声明;例子如下;
//预解释:var num1;
console.log(num1);//->undefined
var num1 = 12;
console.log(num2);//->Error:num2 is not defined
num2 = 12;
关系:在全局作用域下,var num1=12,不仅仅是增加了一个全局变量,而且还相当于给window增加了一个叫做num1的属性名 -> window.num1=12;
var num1 = 12;
console.log(num1);//12
console.log(window.num1);//12
num2 = 13;
console.log(num2);
console.log(window.num2); //我们可以把window.省略;
下面是函数内带var和不带var的;
console.log(total); //undefined
var total = 0;
function fn() {
console.log(total); //undefined
total += 100;
var total = 200;//total是被保护的;
console.log(total); //200
}
fn();
console.log(total); //0
下面是不带var的
console.log(total);//undefined
var total = 0;
function fn(num1, num2) {
console.log(total);//0 ->total不是私有的,找全局下的total,也就是在这里出现的所有的total其实应该都是全局的
total = num1 + num2;//->全局的total=300
console.log(total);//300
}
fn(100, 200);
console.log(total);//300
JavaScript中的顶级作用域是谁?
顶级作用域是Global;数据引用高程三133页;
目前只有nodeJs这个语言可以访问到global;nodeJs中是进程;叫process;后台编程中是不管浏览器的事的,node中是global;JavaScript中只可以访问到window;
window相当于global的代理人;好比上帝和教皇的关系;一般在JS中说的全局变量都是window;全局变量就是window的属性;通过window.varName可以访问到;
但并不是所有的都属于window的,比如Object,Math,String,Function等这6个包装类,就不属于window的属性;和window是无关的;类似于中国党政军的关系;互相独立的;
window只是前端编程里的顶级作用域;
变量和属性有什么关系
全局变量是window的属性;window的属性也可以看做全局变量;一个对象的属性,也可以看做以这个对象为作用域下的变量with语句;
如下: