JavaScript变量、作用域
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了JavaScript变量、作用域,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含11974字,纯文字阅读大概需要18分钟。
内容图文
JavaScript变量、作用域 / 2-1 查漏补缺
查缺补漏: ? ? 变量: 可修改的保存数据的容器。 ? 变量的命名: $ _ 字母 数字,只有数字不能开头,关键字保留字页不能开头。 jQuery:$.each(); underscore:_.each();//这也是一个js的函数库。 $ == jQuery; 区分大小写。 关键字:if,for等。 保留字:class等。 命名要有意义,单词,可以用下划线或驼峰法连接。 i/j/k用于计数循环。 ? 变量的声明:JavaScript变量、作用域 / 3-1 数据类型和堆栈
数据类型和堆栈: ?数据类型:
基本类型:Number,String,Bollean,Undefined,Null;
引用类型:[],{};
基本类型值不可修改,基本类型值只能被覆盖,引用类型值可修改、添加、删除,覆盖不等于修改。
基本类型调用方法时,会找到对应的包装对象,如数字1的包装对象就是Number,字符串"str"的包装对象是String,它们的方法和属性都在这个包装对象上。
堆栈:
数据最开始是保存在硬盘上,当程序运行时,数据将会到内存中,操作速度更快,
内存分为堆内存和栈内存两种。
栈内存从下往上0开始有序排列,都是用来保存变量的,但每个大小都是固定的。
堆内存无序排列,大小不固定。
基本类型保存在栈内存中。
引用类型保存在堆内存中。
访问基本类型的变量时,直接在栈内存的找到,读取值即可。
访问引用类型的变量时:
通过地址访问,地址都是固定大小的,将引用类型的地址(引用地址)保存在栈内存中,再通过地址来定位到引用类型的对象。
保存地址的栈有个名字,那个就是变量名。
引用类型的变量保存的其实是地址
JavaScript变量、作用域 / 3-5 变量比较和值的复制
变量相等的比较: ? 基本类型和基本类型的比较: 参考之前的js基础知识。 ? 引用类型和引用类型的比较: 例子:var xm = { age: 18, score: 4 } var xh = { age: 18, score: 4 } console.log(xm === xh);//false var xm = { age: 18, score: 4 } var xh = xm; console.log(xh === xm);//true
即使值都是相同的,但是指向的是两个不同的空间,所以===是false。第二个例子。xh得到了xm的地址,指向的是同一个空间,所以===是true。 ? 如果只想判断值是否相等,则需要遍历循环里面的内容来做比较:
function equalObjs(a, b) { for(var p in a) {//p表示对象的属性,in后面表示该对象,这里指a对象 if(a[p] !== b[p]) return false; } return true; } console.log(equalObjs(xm, xh));
? js对象取值的两种方式:
var obj = {abc: "ss",nn: 90} var v1 = obj.abc;//使用点的方式 var v2 = obj["abc"];//使用[]的方式 如果key是变量的话就不能使用点了,js会理解变量为对象的key值,造成混淆。 function equalArrays(a, b) { if(a.length !== b.length) return false; for (var i = 0; i < a.length; i++) { if(a[i] !== a[i]) return false; } return true; }
? 基本类型的值的复制:
var xm = 2; var xh = xm; xm++; console.log(xm === xh); console.log(xm); console.log(xh);
? 引用类型的值的复制:
var xm = { age: 18, score: 4 } var xh = xm; xm.age++; console.log(xh === xm); console.log(xm);// console.log(xh);
控制台: false 3 2 true {age: 19, score: 4} {age: 19, score: 4} ? 创建一个独立的对象,改变值不会受影响的那种:
function copyObj(obj) {//浅拷贝,不完善,$.extend()即可浅拷贝,又可深拷贝,可参考 var newObj = {};//保存新的对象 for(var p in obj) { newObj[p] = obj[p];//这里是基本类型的复制 } return newObj; } xh = copyObj(xm);//类似继承 console.log(xm === xh);
1、==比较的是值,===比较的是值和类型;
2、引用类型值的变量比较的是地址,只有指向同一个对象,才表示两个变量相等;
3、数组[4]和数字比较的时候,先通过toString方法转换成字符串'4',这个时候就变成了字符串和数字的比较,此时会将字符串转换成数字再比较。
等等(两个等号)的时候会进行转换,但是不能说一定会转换成number类型。
类型转换的规则可以参考如下:
(1)如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。
(2)如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。
(3)如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。
(4)如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。
? [4]==4 --》true []==[]--》false [4]==[4]--》false ==比较的是值,且引用类型值的变量比较的是地址,只有指向同一个对象,才表示两个变量相等; 数组[4]和数字比较的时候,先通过toString方法转换成字符串'4',这个时候就变成了字符串和数字的比较,此时会将字符串转换成数字再比较。 下面的2个都是地址之间的比较,所以不等。 ?JavaScript变量、作用域 / 3-10 参数传递和类型检测
参数传递和类型检测:
参数传递:
function addTen(num) { return num + 10; } var score = 10; console.log(addTen(score));//num = score;复制了一份,score在外面依然还是10,而addTen(score)是20.
function setName(obj) { return obj.name = 'xm'; } var person = {}; setName(person); console.log(person.name);//obj = person;这里obj和person是同一个东西,里面改变了,外面的也随之改变。
function setName2(obj) { var obj.name = 'xm'; obj = {};//这里在堆内存中开辟了新的不同的空间,在里头进行改变时已经影响不到之前的obj了。 obj.name = 'xh'; } var person = {}; setName2(person); console.log(person.name);//这里打印的是xm
类型检测:
typeof
console.log(typeof 4);//number console.log(typeof(4));//number console.log(typeof 'str');//string console.log(typeof true);//boolean console.log(typeof undefined);//undefined console.log(typeof null);//Object console.log(typeof []);//Object console.log(typeof {});//Object console.log(typeof function () {});//function console.log(typeof /a/);//Object,这个在某些浏览器会显示function
instanceof(含义:前面的是后面的实例)只能和引用类型使用,基本类型使用一定会返回false。
console.log([] instanceof Array);//true console.log([] instanceof Object);//true console.log({} instanceof Object);//true console.log({} instanceof Array);//false console.log( 1 instanceof Number );//false
? null instanceof Object;//false 而 typeof(null);//Object 这是由Javascript规范规定的,Null和Object都是javascript中的数据类型。 Null数据类型只有一个值:null。就像undefined数据类型只有一个值:undefined。 问题出在typeof操作符的定义规范, 对于Null类型的值(只有null),规范就是定义返回"object"这个字符串。但是本质上Null和Object不是一个数据类型,null值并不是以Object为原型创建出来的。 所以null instanceof Object是false。 ?
JavaScript变量、作用域 / 4-1 全局作用域和局部作用域
全局作用域和局部作用域:
1,变量的生命周期。
2,哪里可以访问到变量。 js中的局部作用域也就是函数作用域。(js中没有块级作用域{},if和for后面的{}声明的变量都是全局变量)函数体内部的执行环境。
全局变量:当所有的程序执行完毕后,整个全局作用域被销毁才会清除。
局部变量:出了函数以后就消失。
for(var i = 0; i < 5; i++){//没有块级作用域 var sum; console.log(sum);//第一次执行时undefined,之后和数字进行计算,转化成了NaN sum += i; } console.log(i);//i是全局变量 console.log(sum);//sum是全局变量
?
函数中若没有使用var声明的变量,为全局变量。
若变量未声明就使用才会报错。
函数中的全局变量,若未调用函数,也无法在全局中使用。
var x=y=1;这句话可以转化为这样,y=1,var x=y;
JavaScript变量、作用域 / 4-4 变量对象和作用域链
变量对象和作用域链: 全局作用域的变量对象是window。 不存在变量调用会报错,但不存在的属性,调用不会报错,只会告诉你是undefined。 ?//变量对象 var name = 'xm'; function fn(argument) { var sex = 'male'; function fn2(argument) { var age = 18; console.log(fn2.age);//错误 } fn2(); console.log(fn.sex);//错误 console.log(fn.fn2);//错误 } fn(); console.log(window.name === name);//true console.log(window.fn === fn);//true console.log(person);//不存在这个变量,报错 console.log(window.person);//调用不存在的属性,不会报错,返回undefined
1、name为全局变量,而全局的对象为window,所以window.name是可以直接访问的。
2、fn中的变量以及函数都是局部的,而局部作用域中的对象是没有办法访问的,所以局部的属性和方法也没有办法访问,也就是上面fn.sex写法是错误的。
3、可以使用构造函数来完成:
?作用域链:
当我们在某个作用域中查找变量的时候,查找的过程是会沿着作用域链来进行的。
首先在当前作用域下查找,如果有,和外面的作用域就没有关系,如果没有,就会到上层的作用域查找。
只会往外查找,不会往内查找。 所以同名的变量,越内层,优先级越高。
下图为作用域链的表示:
在for循环中添加事件,让事件中的索引和for循环同步,而不是取到for循环中i的最大值:
在for循环的时候,已经给每一个按钮绑定了点击事件,也就是:
btns[0].onclick=function(){}
btns[1].onclick=function(){}
btns[2].onclick=function(){}
这时候i值已经变成了3,所以在执行点击事件的时候,i+1变成了4。
循环和点击事件并不是一起执行的,循环中的i与弹出的i并不是在一个作用域中的,所以值是不一样的。
这道理考察的是变量的作用域,也就是i的作用域问题,如果保证每一个i值的作用域与点击事件的i作用域相同,那么弹出来的值就会与按钮中的值相对应,
参考: 使用立即执行函数来完成,这样传入的i参数就是局部变量,在执行点击事件时,就会找到局部变量中相对应的i值,而不是外层循环之后的i值。
<button>1</button>
<button>2</button>
<button>3</button>
<script type="text/javascript">
var btns = document.getElementsByTagName('button');
for (var i = 0; i < 3; i++) {
btns[i].onclick = function () {
alert(i + 1);
};
// }
这里循环只是将函数绑定到按钮上,点击按钮时执行alert(i),但i已经变为了3,所以会全部输出3,可以试试下面两种方法;
//1. 用匿名函数传递i值
for(var i = 0; i < 3 ; i++){
(btn[i].onclick = function(){
alert(i);
})(i);
}
//2. 将i值保存为一个属性值
for(var i = 0; i < 3 ; i++){
btn[i].index = i;
btn[i].onclick = function(){
alert(this.index);
};
}
JavaScript变量、作用域 / 4-9 JS解析机制-预解析
js解析机制: ?解析过程:
1,预解析。
2,逐行解读代码。
函数内的参数和局部变量同等对待。
预解析时,会现在全局作用域下进行预解析,【js中函数的预解析优先于变量的预解析】预解析并不会执行函数内部的代码,只是外部声明。
先查找function,后面的同名function覆盖前面的同名funciton,查找完function后,查找window下的所有的var赋值为undefined,完了全局,再进行局部作用域的预解析。
预解析完了,开始逐行读代码。为变量赋值,遇到函数直接跳过,因为之前已经声明完了。
若是函数名与变量名冲突了,预解析时,变量若是没有赋值,那么函数更大,函数保留;
若是变量有赋值,不为undefined,优先预解析函数,再解析变量,后解析的将会被保留在程序中。
var name = 'xm'; function name() { var name = 'xh'; } console.log(name);//打印xm
var name; function name() { var name = 'xh'; } console.log(name);//打印function name() {}
相同等级,谁在后面就留谁。
不推荐在代码块if/for中定义函数,要么到全局,要不就当变量的方法(某些老版本浏览器无法解析代码块中的函数)
函数内部的参数和变量也会被预解析
JavaScript变量、作用域 / 4-13 JS解析机制详解
预解析是分标签进行的。
一个script标签内部解析完,再解析下一个script标签。
参数相当于有var的局部变量。
以下为题目:
<script>
// 1.JS作用域问题一
// ①
// console.log(a);
// var a = 1;
// ②
// console.log(a);
// a = 1;
// 2.JS作用域问题二
// ①
// console.log(a);
// var a = 1;
// console.log(a);
// function a() {
// console.log(2);
// }
// console.log(a);
// var a = 3;
// console.log(a);
// function a() {
// console.log(4);
// }
// console.log(a);
// a();
// 预解析
// function a() {
// console.log(4);
// }
// 3.JS作用域问题三
// ①
// 4.JS作用域问题四
// ①
// var a =1;
// function fn() {
// console.log(a);
// var a =2;
// }
// fn();
// console.log(a);
// ②
// var a = 1;
// function fn() {
// console.log(a);
// a = 2;
// }
// fn();
// console.log(a);
// ③
// var a = 1;
// function fn(a) {
// console.log(a);
// a = 2;
// }
// fn();
// console.log(a);
// ④
// var a = 1;
// function fn(a) {
// console.log(a);
// a = 2;
// }
// fn(a);
// console.log(a);
</script>
<script>
// var a = 1;
</script>
<script>
// console.log(a);
</script>
JavaScript变量、作用域 / 5-1 垃圾收集机制
垃圾收集机制: 程序中会运用到许多数据,数据在内存中都会占用一定的空间,没用的就是垃圾,还会继续驻留在内存中,内存被占用,可用的内存空间就会越来越小,耗尽内存,系统就奔溃了。所以要收集垃圾,释放无用的数据,回收内存。 1,自动收集。 2,手动收集。 垃圾收集的原理: 找到没用的数据,打上标记,释放其内存。按一定的时间间隔周期性执行。 ? 标识无用数据的策略: ? ? 1,标记清除: 垃圾收集器在运行时,会给存储在内存中的所有变量一次性全部加上标记,之后,去掉环境中的变量(变量还未离开它的执行环境),以及被环境中的变量所引用的变量的标记,剩下被标记的就是已经离开环境的变量,将会被清除。(几乎所有浏览器的js垃圾收集都是使用这一方式) ? ? 2,引用计数:( 大多数浏览器放弃了,循环引用会出现问题,你中有我,我中有你,ie浏览器678中dom和bom由c++的COM基础上实现,不是原生的,引用的是引用计数的方式) ? ? 解决循环引用: 将引用的属性或变量设置为null;次数将变为0,就清除了。JavaScript变量、作用域 / 5-4 管理内存
管理内存: web浏览器 < 桌面应用程序。 ? ? 解除引用: 设置为null;适用于大多数全局变量。? ?
内容总结
以上是互联网集市为您收集整理的JavaScript变量、作用域全部内容,希望文章能够帮你解决JavaScript变量、作用域所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。