js变量,作用域

187 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

原始值与引用值

  • ECMAScript变量可以包含两种不同类型的数据:原始值和引用值。原始值就是最简单的数据,引用值则是由多个值构成的对象

动态属性

//引用值
let person = new Object()
person.name = "hello"
console.log(person.name)    //hello

//原生值
let name = "hello"
name.age = 20
console.log(name.age)    //undefiend

原始类型的初始化可以使用原始字面量形式。如果使用new关键字,则会创建一个Object类型的实例,但其行为类似原始值

let name1 = "hello"
let name2 = new String("name2")
name1.age = 20
name2.age = 20
console.log(name1.age)    //undefiend
console.log(name2.age)    //20
console.log(typeof name1)    //String
console.log(typeof name2)    //Object

复制值

  • 原始值复制,复制后的值与复制前的值是两个值,互不干扰
let num = 5
let num2 = num
  • 引用值复制,复制的值实际上是一个指针,指向堆内存中的对象
let obj1 = new Object()
let obj2 = obj1
obj1.name = "hello"
console.log(obj2.name)    //"hello"
erDiagram
Object ||--|{ obj1 : Object
Object ||--|{ obj2 : Object

传递参数

  • 按值传递参数,值会被复制到一个局部变量
function add(num){
    num += 10
    return num
}

let count = 20

let result = add(count)

console.log(count);    //20没有变化
console.log(result);   //30
  • 按引用传递,值在内存的位置会被保存到一个局部变量,本地变量的修改会反映到函数外部
function setName(obj){
    obj.name = "hello"
}

let result = new Object()
setName(result)
console.log(result.name);    //hello

执行上下文与作用域

  • 上下文代码在执行的时候,会创建一个作用域链,决定了访问变量和函数时的顺序
var color = "blue";

function chang() {
  if (color === "blue") {
    color = "red";
  } else {
    color = "blue";
  }
}
chang()

函数chang()的作用域包含两对象,一个是自己的变量对象(arguments),还有一个就是全局上下文变量对象,函数内部可以访问color,就是因为可以在作用域链中找到它

  • 局部作用域中定义的变量可以在局部上下文中替换全局变量
var color = "blue";

function chang() {
  let herColor = "red";

  function Colors() {
    let tem = "antColor";
    herColor = color;
    color = tem;
    
    //这里可以访问color, herColor,tem
  }
  //这里可以访问color, herColor,访问不到tem
  Colors()
}
//这里可以访问color
chang();

image.png

总结

  • 执行上下文分全局上下文,函数上下文,块级上下文
  • 代码每进入一个新上下文,都会创建一个作用域,用于搜索变量和函数
  • 函数或块可以访问自己的作用域内的变量,还能访问全局的
  • 全局上下文只能访问自己的