js变量作用域,变量提升和函数传参

参考:

https://blog.csdn.net/alokka/article/details/88532347 (全局作用域,局部作用域,块作用域)

https://blog.csdn.net/qq_39712029/article/details/80951958 (变量提升)

全局作用域

1,用 var 在全局(函数外)声明的所有变量,都具有全局作用域,即: 网页中所有脚本和函数均可使用。

var carName = " Volvo";
// 此处可调用 carName 变量
function myFunction() {
    // 函数内可调用 carName 变量
}

2,没有声明的变量(没有使用var)会自动提升到全局作用域

如果是在函数里面,需要执行函数才能生效,并且也只有在函数执行后面的作用域才能使用

//情形1
console.log(op1);//会报错
op1='ddd';
console.log(op1);

//情形2 
console.log(op2);//undefined
var op2='ddd';//因为变量有提升
console.log(op2);//ddd

 
//情形3
console.log(carName)//会报错
function myFunction() {
    carName = "Volvo";
    // 此处可调用 carName 变量
}
//需要执行myFunction后才能使用

 

局部作用域(即函数作用域别去追究)

1,函数内部什么定义的变量,只在函数内使用;

2,生命周期:在函数调用时临时生成,调用结束后就释放;

 

块作用域

JS中作用域有:全局作用域、函数作用域,没有块作用域的概念。

支持块级作用域的编程语言:java,c++,c
不支持块级作用域的编程语言:javascript,php,python

for(var i = 0; i < 4; i++) {
        var d = 5;
    };
console.log(i);    // 4   (循环结束i已经是4,所以此处i为4)
console.log(d); // 5

但是es6新增了块作用域,即使用let和const实现块作用域;

for(let i = 0; i < 4; i++) {
  const d=i;
  console.log(d);//0,1,2,3,说明每次循环体内,都是一次新的作用域
};
console.log(i);  //会报错
console.log(d); //会报错

 

变量提升

1,js代码自上而下执行之前,浏览器首先会把当前上下文中所有带“var / function”关键字进行提前的声明和定义,解析到它们对应作用域开始的位置,这种预先处理的机制叫做变量提升,变量提升的意义在于创建变量前使用这个变量不报错。

2,变量提升也可以称之为预解析。可以理解为这是词法解析的一个环节,语法解析发生在代码执行前;

3,JavaScript 仅提升声明,而不提升初始化;

4,函数和变量相比,会被优先提升

变量提升

我们习惯将var a = 2;看做是一个声明,而实际上javascript引擎并不这么认为。它将var a和a = 2看做是两个单独的声明,第一个是编译阶段的任务,而第二个则是执行阶段的任务。

例子1:

console.log(v1);
var v1 = 100;
function foo() {
    console.log(v1);
    var v1 = 200;
    console.log(v1);
}
foo();
console.log(v1);

//结果
//undefined //undefined //200 //100

实例2:

var name = "world";
(function(){
  if(typeof name === "undefined") {
    var name = "Jack";
      console.log("Hello " + name);
  } else {
    console.log("Hello " + name);
  }
}());

//解析:相当于
var name = "world";
(function(){
  var name; // 变量提升,仅提升声明,不提升初始化
  if(typeof name === "undefined") {
    name = "Jack";
    console.log("Hello " + name);
  } else {
    console.log("Hello " + name);
  }
}());

函数提升

 javascript中不仅仅是变量声明有提升的现象,函数的声明也是一样;具名函数的声明有两种方式:

//函数声明式,函数提升是整个代码块(相当于申明和初始化都提升了)提升到它所在的作用域的最开始执行
function bar () {}
//函数字面量式,这种情况和变量提升是一样的 var foo = function () {}

实例1

foo(); //1 ,因为函数提升比变量提升更优先
 
var foo;
function foo () {
    console.log(1);
}

foo = function () {
    console.log(2);
}

变量的值传递和引用传递

// 基本类型
var num1 = 5;
var num2 = num1;
num2 = 10;
console.log(num1 + ' | ' + num2); // 5 | 10

// 引用类型
var obj1 = new Object();
obj1.num = 5;
var obj2 = obj1;
obj2.num = 10;
console.log(obj1.num + ' | ' + obj2.num); // 10 | 10

一句话,引用类型复制的是指针的指向。

函数传参

一 ,参数

1, 所有的参数传递,都是传递值的拷贝。(如果想知道为什么,去学习编译原理的函数调用的参数压栈和出栈对应内容)。

2 ,C传指针进去,其实也是把这个指针值按拷贝传送进去。但是因为指针值指向一块外部内存空间(其实更多是堆空间,或外层栈变量空间),所以感觉可以在函数里改变外部变量。其实本质还是按拷贝传递,只是传递进去的是一个访问变量的渠道。
因此,如果我们希望函数内能改变外部的指针值,往往传进去的是指针变量的指针。呵呵,很多初学C的程序员,对**非常难理解。

二 ,返回值

返回值是按拷贝传递,函数出栈后,会传出一个值,该值在调用函数的代码段的生命周期里一直有效。相当与调用点形成一个匿名的栈变量。
变量a = function(); 而a并不等于函数里return的那个值。
其实function()执行结果自身就是一个匿名变量。(其实编译器会检查语法,如上面a=function这样的语法,匿名变量不会生成,直接使用a变量拷贝返回值)
例如: function()返回int值。 完全可以 int x = function() + 6;//注意:+运算时,函数已经执行完毕,所有函数出栈操作已经结束。
很明显function()必须有一个变量或常量参与计算,而函数里return的值会随函数调用结束出栈而被删除,所以必须拷贝构造传递出来。

上代码:

var a = {
num:'1'
};
var b = { num:'2' }; function change(obj){ //obj.num = '3';// obj = {
num:'3'
}; return obj.num; } var result = change(a); console.log(result + ' | ' + a.num); // 2 | 3
posted @ 2019-04-02 09:47  小匡程序员  阅读(1195)  评论(0编辑  收藏  举报