1.JavaScript hoisting(变量/函数 提升)
以下实验都是通过firefox的Console做的实验.
之前变量没有定义的错误没了,取而代之的是告诉我们a的值是 ‘undefined‘.
先不管a的值缘何为 ‘undefined‘ 了,至少可以知道现a这个变量是定义了,因为之前报的‘ a is not defined‘的错误没有了。
这正是因为JavaScript 中的一个声明提升的特性起的作用。
JavaScript中可以提前使用在后面语句中声明的变量,这种特性叫被国外某网友(ben cherry)称为Hoisting (非官方术语) 。
我在<<javascript 模式>> 一书中看到该词被翻译为 "提升" ,指的的就是变量声明提前 .可以理解为将变量的声明提前了,所以在变量声明前使用变量不会报错。而且这一特性不仅限于变量名,对于函数的声明也是同样的效果。
第一次对函数foo()的调用同样报 ‘not defined‘ 错误。这是合情合理同时是合法的。因为从头到尾就没有定义这么一个叫作foo() 的东西。
之后将函数调用写在最前面,但函数的定义我们写在了之后。
发现正常输出了我们想要的内容.
这里需要深入理解Hoisting这一特性。它的提前只是将声明提前,而对变量的赋值并没有跟着提前。
也就是为什么我们可以在第一句使用变量a但它的值却是 ‘undefined‘。 JavaScript里面声明了但还未赋值的变量其值默认便是 ‘undefined‘。
按照Hoisting来解释,最终生成的等价代码其实差不多应该就是这样的:
var a ;
console.log(a);
a = 1;
1.匿名函数无法在声明前调用
但仅限于上述这种方式定义的函数。对于匿名函数上述规则不适用。
2. 参数变更影响到函数外部
当传递给函数的参数是一个数组或对象时,在函数体内对这个传入的参数的更改会影响到函数体外的原传入值。
一般说来,对参数的更改不会影响到原来变量的值,更改只在函数体内起作用,这个主要原因是javascript变量传递都是按值传递的.将变量的值进行复制,然后传入到函数内部处理.但是对于对象和数组则有所不同.
当传入的参数是数组、对象时,在函数体内对参数所做的更改会反映到原变量上。
function myFunc(theObject) { theObject.make = "Toyota"; } var mycar = {make: "Honda", model: "Accord", year: 1998}, x, y; x = mycar.make; // x gets the value "Honda" myFunc(mycar); y = mycar.make; // y gets the value "Toyota" // (the make property was changed by the function) console.log(x ); console.log(y);
可以看出,上面代码中已经把mycar 对象的make属性修改了.
当在函数体内对传入的数组或对象赋值时,这个更改不会反映到函数体外的原变量身上
下面是关于对象的例子:function myFunc1(theObject) { theObject = {make: "Ford", model: "Focus", year: 2006}; } var mycar = {make: "Honda", model: "Accord", year: 1998}, x, y; x = mycar.make; // x gets the value "Honda" myFunc1(mycar); y = mycar.make; // y still gets the value "Honda" console.log(x); console.log(y);
按照上面函数内部的更改会反映到原变量的理论。但结果让人有点难以接受。
真的,我内心真的"此起彼伏"啊.
原因在于,当在函数体内使用赋值操作时,系统就创建了一个变量名为theObject的变量。这个theObject是函数内部的变量,对它进行赋值当然只在函数体内起作用,外面的myCar还是原来的myCar。
这一步与原来代码的操作差别仅在于在函数体内是对参数赋新值呢还是对参数的属性或数组的元素进行更改。
以上内容来自MDN 中关于javascript的文章.链接地址为:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions
Best wishes.