《二》Javascript 中的变量

变量:可变化的量,用来存储数据。

使用 var 关键字来定义变量。

// 使用 var 来定义变量
var year = 2017: // 正确

// 变量也可以不使用 var 声明直接赋值
year = 2017;
console.log(year) // 正确

// 不定义变量直接使用会报错
console.log(month);// 错误。报错 month 不存在,但 typeof 返回 undefined 

// 可以使用一个 var 定义多个变量,用逗号分开
var year = 2017, month = 07; // 正确

变量的命名遵守标识符的命名规则。

优秀的变量命名法:

  1. 驼峰命名法:mathTestScore
  2. c 风格:math_test_score
var year = 2017; // 正确
var 2017year = 2017; // 错误

可以在声明变量的同时对它使用等号进行赋值;没有赋值的变量默认取值为 undefined。

// 声明变量并赋值
var box=100;
console.log(box); // 打印 100

 // 声明变量不赋值
var box;
console.log(box); // 打印 undefined

变量可以初始化后再次改变(可以同时改变为不同的类型),但对于后期维护带来困难,而且性能也不高,导致成本很高。

ECMAScript 的变量是弱类型的。
所谓弱类型就是可以用来保存任何类型的数据,声明变量时不需要指定变量的类型,根据变量的值确定。

var box = ”小米”;
box = 100; // 不需要重复地使用 var 来声明同一个变量
console.log(box) // 打印100

全局变量和局部变量:

  1. 全局变量:定义在所有函数之外,作用于整个代码的变量。
  2. 局部变量:定义在函数体内,只作用于函数体的变量。

使用 var 声明的变量会自动被添加到最接近的环境中。
不使用 var 声明直接赋值的变量,无论在函数体内还是函数体外都是全局变量(不推荐)。
访问局部变量要比访问全局变量更快,因为不用向上搜索作用域链。

var box=’blue’; // 全局变量
function setBox(){
    var box=’red’; // 局部变量,范围在 setBox() 里
    console.log(box);        
 }
setBox(); // 打印 red       
console.log(box); // 仍然打印 blue
var box=’blue’;
function setBox(box){ // 通过传参,但也是局部变量,范围在 setBox() 里
      console.log(box);
}
setBox(‘red’); // 打印 red 
console.log(box); // 仍然打印 blue

变量的值的类型:

ECMAScript 变量的值包含两种不同的类型:基本类型和引用类型。

将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。

基本类型值指的是保存在栈内存中的简单数据,源自5种基本数据类型:undefined、null
、string、number、boolean,基本类型值完全保存在内存中的一个位置,占有固定大小的空间,按值来访问(可以操作保存在变量中的实际的值)。

引用类型值是指保存在堆内存中的对象,指 object。由于这种值的大小不固定,因此必须在堆内存中为这个值分配空间,但内存地址大小是固定的,因此可以将内存地址保存在栈内存中。也就是说,变量中保存的实际上只是一个指针,指向堆内存中真正保存数据的位置。按引用访问(js 不允许直接访问堆内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上操作的是对象的引用而不是真正的对象。先从栈中读取内存地址,再通过地址找到堆中的值)。

动态属性:

定义基本类型和引用类型都是创建一个变量并为该变量赋值。但是基本类型的值无法添加属性。

var box={name: '小米’} // 创建引用类型
console.log(box.name) // 小米
var box=’小米’ // 创建基本类型
box.age=28 // 添加一个属性
console.log(box.age) // undefined

变量复制:

在变量复制方面,不管是基本类型还是引用类型,复制的都是栈内存的数据,堆内存的数据无法复制。基本类型复制的是值本身,引用类型复制的是地址。

从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本。
从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同一个对象。

var box=’小米’
var box2=box
console.log(box2) //小米

var box=’小米’
var box2=box
box=’kkk’
console.log(box2) //小米
console.log(box) // kkk。box2 是 box 的一个副本,但是基本类型是完全独立的。box 和 box2 两个变量分别操作时互不影响。
var box= {name: '小米’}
var box2=box // 把引用地址复制给 box2
box2.name=’kkk’ // 给原有的对象添加属性
console.log(box2.name) // kkk
console.log(box.name) // kkk。因为指向的是同一个 object,不管修改谁, 都会改变。

var box= {name: '小米'}
var box2=box
box = {age: 18} // 赋值了一个新的对象。box 保存的引用地址和 box2 保存的引用地址已经不一样了,指向的对象也不一样。
console.log(box2) // {name: '小米’}

在这里插入图片描述
有一个数据 {name: 'Tom'} 存储在堆内存中;现在,声明一个变量 obj 并将 {name: 'Tom'} 赋值给它,实际上 obj 中存储的是 {name: 'Tom'} 在堆内存中的地址 0x123;现在,声明一个变量 obj1 并将 obj 赋值给它,实际上就是将 obj 中保存的值,也就是 {name: 'Tom'} 在堆内存中的地址 0x123 赋值给了 obj1。

传递参数:

ECMAScript 中所有函数的参数都是按值传递的。基本类型传递的是值本身,引用类型递的是地址。

var count=50
function box(count1){
	 count1 = count1 + 10
}
box(count))
console.log(count) //50。在调用函数时,变量 count 作为实参被传递给函数,于是数值 50 被复制给了形参 count1

var obj = {name: 'Tom'}
function box1(obj1) {
	obj1.name = 'Mary' // 给原有的对象添加属性
}
box1(obj)
console.log(obj) // Mary。在调用函数时,变量 obj 作为实参传递给函数,于是 obj 的内容,即地址值被复制给了形参 obj1,obj1 和 obj 指向同一个对象

var obj= {name: '小米'}
function box(obj1){
	obj1 =  {name: 'kkk'} // 赋值了一个新的对象
}
box(obj)
console.log(obj) //小米。在函数内部,给 obj1 赋值了一个新的对象,obj1 和 obj 指向的已经不是同一个对象了,因此 obj 并未更改。

类型检测:

  1. typeof:可以使用 typeof 运算符来检测一个值或者变量的数据类型。

    typeof 在检测基本数据类型的时候好用,但检测引用类型的时候,并不能具体检测到到底是什么类型的 Object 对象。

    var box=’Lee’
    console.log(box, typeof box);// 'Lee' 'string'	 
    
    var box={}
    console.log(box, typeof box) // [object Object] 'object'
    
    var box = []
    console.log(box, typeof box) // Array(0) 'object'
    
  2. instanceof:使用 instanceof 运算符检测引用类型,来判断对象的具体类型。
    语法:A instanceof B,实例对象 A 是否是构造函数 B 的实例对象。如果 B 函数的原型对象在 A 对象的原型链上,就返回 true,否则返回 false。

    function Foo(){}
    var f1 = new Foo()
    console.log(f1 instanceof Foo) // true
    console.log(f1 instanceof Object) // true。这是因为 Object.prototype 是原型链的终点
    

    请添加图片描述

console.log(Object instanceof Function) // true
console.log(Object instanceof Object) // true
console.log(Function instanceof Function) // true
console.log(Function instanceof Object) // true

请添加图片描述

// 使用 instanceof 运算符检测基本类型,会返回 false
var box='Lee'
console.log(box instanceof String) // false
// 以对象的形式处理基础类型,使用 instanceof 运算符检测会返回 true
var box=new String('Lee')
console.log(box instanceof String) // true

相等判断:

基本类型值进行相等判断时,会比较值是否相等。引用类型值进行相等判断时,会比较地址是否相等。

var num1 = 1
var num2  = 1
console.log(num1 == num2) // true

var arr1 = [1, 2, 3]
var arr2 =  [1, 2, 3]
console.log(arr1 == arr2) // false

var obj1 = {name: 'Lee'}
var obj2 = obj1
console.log(obj1 == obj2) // true

变量声明提升:

把变量声明提升到当前执行上下文的最顶端,只提升声明,不提升值。也就是说,通过 var 定义的变量,在定义语句之前就可以访问到,值为 undefined。

JS 引擎在读取 JS 代码时会进行两个步骤,第一个步骤是解释,第二个步骤是执行。
所谓解释就是会先通篇扫描所有的 JS 代码,然后把所有声明提升到顶端,第二步是执行,执行就是操作一类的。

在执行全局的代码前或者调用函数时,JS 引擎会先创建一个对应的执行上下文,在创建对应的执行上下文时,会创建一个变量对象并把变量声明、函数声明、函数的形参都会被添加到这个对象中。所以在代码执行之前就可以访问到。

作用域提升:在作用域内,可以被提前访问。
因此,变量声明提升和函数提升也都可以被称为是作用域提升。

console.log(a) // 输出 undefined
var a = 10

//相当于
var a
console.log(a) // 由于未赋值,所以输出 undefined 
a = 10
console.log(a) // Uncaught ReferenceError: a is not defined
a = 10
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值