JS变量+作用域
基本类型-栈内存
保存基本类型的变量保存的是值本身
引用类型-堆内存
保存引用类型的变量保存的并不是对象本身,而是一个指向该对象的引用地址
引用类型判断对象是否相等
function equalObjs(a, b) {
for (var p in a) {
if (a[p] !== b[p]) return false;
}
return true;
}
console.log(equalObjs(xm, xh));
引用类型判断数组是否相等
function equalArrays(a, b) {
if (a.length !== b.length) return false;
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
引用类型对象复制(浅拷贝:只拷贝一层)
function copyObj(obj) {
var newObj = {};
for (var p in obj) {
newObj[p] = obj[p];
}
return newObj;
}
console.log(undefined==null); /*true*/
console.log(undefined===null); /*false*/
从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象,当给变量赋新值时,此变量就不再指向原来的对象了;
数组是引用类型的 , 如题中b=a相当于a与b指向同一个地址 , 但是a=[4,44]之后改变了a的地址 , 所以b不会受到影响 为[4] . 后面又把a=b指向了同一个地址 ,此时为b添加元素 , 因为a、b的地址都没有改变 ,a也会随之改变 ,所以a为[4,44] .
参数传递的本质是值的复制,由于person是引用类型,这里就相当于把person的地址复制给了函数setName的参数obj
function setName(obj) {
obj.name = 'xm';
obj = {};
obj.name = 'xh';
}
var person = {};
setName(person);
console.log(person.name); /*xm*/
obj = person
检测变量类型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
instanceof检测引用类型
不能检测基本数据类型,只要是基本数据类型和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
console.log(null instanceof Object);//false
有两个变量,分别是a = {name: 'xm'}, b = [4],我们不用第三个变量来调换a和b的值
var a = {name: 'xm'}, b = [4];
a=[a,b];
b=a[0];
a=a[1];
作用域与解析机制
全局变量容易被污染,少用
with(obj)可以延长作用域链,但不推荐使用
var person = {};
person.name = 'xm';
person.sex = 'male';
var score = 4; with(person) {
name = 'xh';
sex = 'female';
score = 44;
}
console.log(person.name);
console.log(person.sex);
console.log(score);
有3个按钮给每个按钮添加点击事件,希望每次点击时输出当前点击的是第几个按钮,但是目前不论点击哪个按钮,最终输出的都是4
原因:由于先绑定,后触发,给每个按钮绑定事件,但是在触发的时候i已经是循环完之后,i的值了
(1)单击方法导致的循环问题。提示:单击方法在循环外面定义
(2)在循环中调用,并将被点的按钮的型号传进去
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>变量、作用域</title> </head>
<body>
<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);
};
} //正确代码
var btns = document.getElementsByTagName('button');
var fn=function(i){
btns[i].onclick=function(){
alert(i+1);
}
}
for(var i=0;i<btns.length;i++){
fn(i);
}
</script>
</body>
</html>
不存在的变量或函数会报错;不存在的属性或方法,返回undefined;||是短路操作,形如a||b,如果a的值转换成布尔值是true的话,a||b等于a;如果a的值转换成布尔值是false的话,a||b等于b
console.log(person||(person='xm'));
console.log(window.person||(window.person='xm'));
预解析
1. 以var 声明的变量 会预解析 ,赋值为undefined;没有var则不进行预解析
2. 以let 声明的变量 不会进行预解析
3. 函数的声明会预解析 , 函数会被提升,然后从上到下执行代码的时候,输出fn,就是提升的函数
4. 函数表达式不进行预解析
案例1:
(1)
预解析:外层查找var,name和age为undefined
(2)
预解析:内层函数fn,函数在预解析时,已经提前进行了该函数的声明。函数内变量argument、name、age为undefined
(3)
正常执行:外层name从undefined变为’xm’,age从undefined变为18
(4)
正常执行:内层输出name为undefined
(5)
正常执行:内层name从undefined变为’xh’,age从undefined变为10
var name = 'xm';
var age = 18;
function fn(argument) {
console.log(name); //undefined
var name = 'xh';
var age = 10;
}
fn();
如果预解析时变量名与函数名重复,那么只预解析函数
案例2:
console.log(a);
var a = 1;/*var预解析之后是undefined*/
案例3:
console.log(a);
a = 1;/*没有预解析,报错*/
案例4:
console.log(a); //预解析结果a()
var a = 1;
console.log(a); //正常赋值后执行1
function a() {
console.log(2); //函数在预解析之后不再解析
}
console.log(a); //
var a = 3;
console.log(a); //
function a() {
console.log(4);
}
console.log(a); //
a(); //报错,此时a=3,不是函数
案例5:
函数内部没有var,不进行预解析。输出时查找外层a,输出1;赋值时对外层a进行操作
var a = 1;
function fn() {
console.log(a);
a = 2;//修改全局变量a
}
fn();
console.log(a);
案例6:
函数参数也相当于var定义的局部变量,预解析为undefined。赋值时对参数a进行操作
var a = 1;
function fn(a) {
console.log(a);
a = 2;/*对参数a进行操作,从undefined变为2,全局变量a没有改变*/
}
fn();
console.log(a);
案例7:
函数参数也相当于var定义的局部变量,预解析为undefined。赋值时对参数a进行操作
var a = 1;
function fn(a) {
console.log(a);//将全局变量赋值给参数,因此参数输出1
a = 2;//将参数从1变成2,全局变量没有改变
}
fn(a);//执行时将全局变量a=1传入参数
console.log(a);//
垃圾收集机制
解除变量引用的方法是将其设置为null
JS变量+作用域的更多相关文章
- [刘阳Java]_步步窥探JS变量作用域
今天的这个文章题目名称甚是让人会突发异想.JS变量作用域是务必需要搞懂的,单从面试过程就会让面试者烧脑壳.所以,我们还是写一篇关于JS变量作用域的技术专题,让所有小伙伴能够借此文章去整理JS的基础学习 ...
- 解释JS变量作用域的范例
JS的变量作用域只有两种:全局作用域与函数作用域. 用var声明的变量不能简单的说是属于函数作用域,应该是说属于其最近的作用域. var a = 10; function test(){ var a; ...
- 浅谈js变量作用域
变量的作用域也是前端面试题常考的一个问题,掌握下面几个规律可以帮你更好的理解js的作用域. 1.作用域优先级遵循就近原则,函数内部的作用域优先级大于外部 var a=456; var b=111; f ...
- js变量作用域--变量提升
1.JS作用域 在ES5中,js只有两种形式的作用域:全局作用域和函数作用域,在ES6中,新增了一个块级作用域(最近的大括号涵盖的范围),但是仅限于let方式申明的变量. 2.变量声明 var x; ...
- javaScript的闭包 js变量作用域
js的闭包 js的变量作用域: var a=90; //定义一个全局变量 function test(){ a=123; //使用外层的 a变量 } test(); document.write(&q ...
- 原型模式故事链(5)--JS变量作用域、作用域链、闭包
上一章 JS执行上下文.变量提升.函数声明 传送门:https://segmentfault.com/a/11... 本次我们主要讲讲变量作用域和闭包变量作用域:顾名思义:变量起作用的范围.变量分为全 ...
- JS变量作用域与解构赋值
用var变量是有作用域的 变量在函数内部声明时,那么该变量只属于整个函数体,函数外不可调用 当两个不同的函数里,使用了用一个相同的变量名,二者不互相影响,相互独立 遇到嵌套函数时,外部函数不可调用内部 ...
- js变量作用域及访问权限的探讨(2)
每一种语言都有变量的概念,变量是用来存储信息的一个元素.比如下面这个函数: 复制代码 代码如下: function Student(name,age,from) { this.name = n ...
- js 变量 作用域及内存
由于Javascript是松散型的,所以其变量只是在特定时间用于保存特定值的一个名字而已,并不存在某个变量必须保存某种类型的值的规则,变量的值以及其数据类型都可以在脚本的声明周期内改变 一.基本类型与 ...
- js变量作用域和闭包的示例
<script> /* js是函数级作用域,在函数内部的变量,内部都能访问, 外部不能访问内部的,但是内部可以访问外部的变量 闭包就是拿到本不该属于他的东西,闭包会造成内存泄漏,你不知道什 ...
随机推荐
- ELK:收集k8s容器日志最佳实践
简介 关于日志收集这个主题,这已经是第三篇了,为什么一再研究这个课题,因为这个课题实在太重要,而当今优秀的开源解决方案还不是很明朗: 就docker微服务化而言,研发有需求标准输出,也有需求文件输出, ...
- 全网一定不是最好懂的C++线性筛素数
Part 0:概念 先给几个概念(很重要): 合数:如果\(xy=z\text{且}x,y\text{为正整数}\),我们就说\(x,y\text{是}z\text{的合数}\) 素数:如果数\(a\ ...
- 阿里云服务器ECS Ubuntu18.04 初次使用配置教程(图形界面安装)
最近由于工作需要,要使用服务器测试,就先自已买了个服务器,就在阿里云买了一个,先买了那个叫虚拟主机的,后来发现不是我需要的,所以退了,就先了这个ECS主机.3年.如果购买就上图了.下面直接进入正题. ...
- Andriod you must restart adb and eclipse
今天看着视频 学习着 andriod ,启动 的时候 竟然报错 我试了N种google来的方法,都失效,现在把我的解决方法告诉大家,希望能帮到大家. 首先,我先罗列下我搜到的方法,大家也可以尝试. 1 ...
- 面试题|手写JSON解析器
这周的 Cassidoo 的每周简讯有这么一个面试题:: 写一个函数,这个函数接收一个正确的 JSON 字符串并将其转化为一个对象(或字典,映射等,这取决于你选择的语言).示例输入: fakePars ...
- iOS开发基础--C语言简述(一)
先占个坑,回来再补 需要的运行环境,自行搜寻,工具不止一种,不详细叙述. C语言是一门非常重要的编程语言,与硬件底层直接相关,很多语言到最后的接口封装都会选择C语言,因而C语言一直很受欢迎,也务必掌握 ...
- vue中子组件触发父组件的方法
网上找了几种方法,下面这两种最实用,最明了 方法一:父组件方法返回是字符串或数组时用这种方法 子组件: <template> <button @click="submit& ...
- Python3标准库:itertools迭代器函数
1. itertools迭代器函数 itertools包括一组用于处理序列数据集的函数.这个模块提供的函数是受函数式编程语言(如Clojure.Haskell.APL和SML)中类似特性的启发.其目的 ...
- SAP S4HANA里委外加工采购功能的变化
SAP S4HANA里委外加工采购功能的变化 [Part 1:主要变化点] 1.1,采购订单界面上的变化, 1.2, 新的事务代码: ME2ON (Subcontracting Cockpit), 1 ...
- 1.4掌握日志工具的使用——Android第一行代码(第二版)笔记
Android中的日志工具类是Log(android.util.Log),这个类中提供了如下5个方法来供我们打印日志. Log.v():用于打印那些最为琐碎的.意义最小的日志信息.对应级别verbos ...