JavaScript语言内部机制概念整理(一)

来源:互联网 发布:网络拓扑结构图片 编辑:程序博客网 时间:2024/06/11 06:33

JavaScript语言内部机制概念整理

第四章

4.1.3参数传递方式

ECMAScript中所有函数的参数都是按值传递,把函数外部的值复制给函数内部的参数,如同把值从一个变量复制到另一个变量。

基本类型值的传递如同基本类型变量的复制,被传递的值会被复制给一个局部变量;

引用类型值的传递如同引用类型变量的复制,把值在内存中的地址复制给一个局部变量(局部变量的变化会反映在函数外部)。

Eg1:传递基本类型值

function addTen(num){//num为函数的局部变量

       num + = 10;

       return num;

}

var count = 20;

var result = addTen(count);//count被作为函数的参数,count和num相互独立,仅仅具有相同的值

alert(count);//20

alert(result);//30

 

Eg2:

function setName(obj){

       obj.name ="Niaco";

}

var person = new Object();

setName(person);//obj和person引用同一对象name,name值得改变会改变person和obj引用的值。

alert(person.name);//Niaco

 

Eg3对象是按值传递的

function setName(obj){

       obj.name ="Niaco";

       obj = newObject();

       obj.name ="Grego";

}

var person = new Object();

setName(person);

alert(person.name);//Niaco

即使在函数内部修改了参数的值,但原始的引用仍旧不变。

当函数内部重写obj时(obj = new Object()),obj变成了函数的局部变量,该局部变量在函数执行完后立即被销毁。

4.2函数的执行环境及作用域

执行环境定义了变量或函数有权访问的其他数据,决定了他们各自的行为。

每个执行环境都有一个与之相关联的变量对象(variable object,代码无法访问),保存环境中定义的所有变量和函数。全局环境是最外围的执行环境,全局执行环境被认为是window对象。

执行环境中所有代码执行完毕后,环境被销毁,相关函数和变量也随之销毁。

每个函数都有只记得执行环境。当执行流进入一个函数时,函数的环境会被推入一个环境栈中,函数执行后,栈将其环境弹出,将控制权返回之前的执行环境。

       代码在一个环境中执行时,会创建变量对象的一个作用域链(scope chain),作用域链保证对执行环境有权访问的所有变量和函数的有序访问。访问顺序由内而外(作用域链的方向),纸质全局执行环境。

标识符解析:沿作用域链一级级搜索标识符的过程。

EG

var color ="blue";

functionchangeColor(){

       if(color === "blue"){

              color = "red";

       }else{

              color = "blue";

       }

}

changeColor();

alert("Coloris now" + clolor);

此例中,函数changeColor()的作用域链包含两个对象:他自己的变量对象arguments和全局环境的变量对象。

局部作用域中定义的变量可以再局部环境中与全局变量互换使用。

var color ="blue";

functionchangeColor(){

       var anotherColor = "red";

       function swapColors(){

              var tempColor = anotherColor;

              anotherColor = color;

              color = tempColor;

              //这里可以访问color、anotherColor和tempColor;

       }

       //这里可以访问color、anotherColor,不能访问tempColor;

       swapColors();

}

//这里只可以访问color

changeColor();

 

延长作用域链

在作用域前段临时增加一个变量对象,该变量对象在代码执行之后被移除。

执行流进入下列语句,作用域链会加长:

try-catch语句的catch块;

with语句。

这两个语句会在作用域链前段添加一个变量对象。

With会将指定对象添加到作用域链中;catch创建新的变量对象,其中包含被抛出的错误对象的声明。

functionbuildUrl(){

       var qs = "?debug=true";

       with(location){

              var url = href + qs;

       }

       return url;

}

Location对象的变量url会变成函数buildUrl的子变量,成了函数执行环境的一部分;变量href可在当前执行环境的变量对象中找到。Location的变量对象被添加到作用域链前端

函数中未用var声明的变量会被自动添加到全局环境,视为全局变量。

   function add(num1,num2){

              var sum = num1 + num2;

              return sum;

}

var result =add(10,20);//30

alert(sum);//无输出

functionadd(num1,num2){

              sum= num1 + num2;

              return sum;

}

var result =add(10,20);//30

alert(sum);//30,sum为全局变量

 第五章 Function类型
函数的调用方式(一般函数、对象的方法、apply、call)及this的指向。
JavaScript函数调用自带两个参数:this和arguments,其中arguments实参数组,非真实数组。
4种调用方式:
函数作为方法调用、使用构造函数调用、作为函数调用、作为函数方法调用(包括call和apply)
每种方式的不同在于this的初始化。
作为一个函数调用:
function myFunction(a,b){
return a*b;
}
myFunction(10.2);//20
此例中myFunction() 与 window.myFunction()同。


this指向函数运行时的当前对象。
函数没没有被自身对象调用时,this的值会变成全局对象。
function myFunction(){
return this;
}
myFunction();//返回window对象
    
函数作为方法调用:
var myObject = {
firstName:”John”,
lastName:”Snow”,
fullName: function(){
return this.firstName+” ”+t his.lastName 
}
}
myObject.fullName();//John Snow
fullName方法是一个函数,也是对象myObject的一个属性。This的值为myObject。
而:
var myObject = { 
firstName:"John",
lastName: "Doe", 
fullName: function () { 
return this; 

}
  myObject.fullName(); // 返回 [object Object] (所有者对象)
函数作为对象方法调用,会使this的值成为对象本身。

使用构造函数调用:
如果函数调用前使用了new关键字,则是调用了构造函数。(看似是创建了新函数,实际上JavaScript函数是重新创建的对象)
function myFunction(arg1,arg2){
this.firstName =  arg1;
this.lastName = arg2;
}
var x = new myFunction(“John”,”Snow”){
x.firstName;//返回John
}
构造函数的调用会创建一个新对象。新对象会继承构造函数的属性和方法。
构造函数中this没有任何的值,this的值在函数调用时实例化对象(new object)时创建。


作为函数方法调用函数
在JavaScript中,函数是对象,有其属性和方法。
call( )和apply( )是预定义的函数方法,两个方法可用于调用函数,他们的第一个参数必须是对象本身。两者作用相同,区别在于接收参数方式不同。
function myFunction(a,b){
return a*b;
}
myObject = myFunction.call(myObject,10,2);//返回20

function myFunction(a,b){
return a*b;
}
myArray = {10,2};
myObject = myFunction.apply(myObject,myArray);//返回20
两个方法都使用了对象本身作为第一个参数。 两者的区别在于第二个参数: apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。
在 JavaScript 严格模式(strict mode)下, 在调用函数时第一个参数会成为 this 的值, 即使该参数不是一个对象。
在 JavaScript 非严格模式(non-strict mode)下, 如果第一个参数的值是 null 或 undefined, 它将使用全局对象替代。
通过 call() 或 apply() 方法你可以设置 this 的值, 且作为已存在对象的新方法调用


   函数的闭包
闭包函数是指有权访问另一个函数作用域中的变量的函数。
创建必报的常见方式,在一个函数内部创建另一个函数。
function createComparisonFunction(propertyName){
return function(object1,object2){//内部函数
var value1 = object1{propertyName};
var value2 = object2{propertyName};
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
};
}   
 内部匿名函数访问了外部函数的参数,其作用域链包含外部函数的作用域。即使内部函数返回或被其他地方调用,它仍能访问propertyName。
作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。
外部函数执行完毕后,其活动对象不会被销毁(其执行环境的作用域链会被销毁,其活动对象仍会留存在内存中,直到匿名函数被销毁),因为内部匿名函数作用域链仍在引用这个活动对象。
闭包只能取得包含函数中任何变量的最后一个值。
function createFunctions(){
var result = new Array( );
for(var i = 0;i<10;i++){
result[i] = function(){
return i;
};
}
return result;//所有返回值均为10
}


function createFunction(){
var result = new Array( );
for (var i = 0;i<10;i++){
result[i] = function(num){
return function(){
return num;
};
}(i);//当前i赋值给num
}
return result;//0-10
}


全局函数中,this等于window;
当函数被某个对象的方法调用时,this等于那个对象。
匿名函数的执行环境具有全局性,因此其this通常指向window。
var name = “the window”;
var object = {
name : “my object”;
getNameFunc : function(){
return function(){
return this.name;
}
}
};
alert(object.getNameFunc()());//the window




var name = “the window”;
var object = {
name : “my object”;
get NameFunc : function(){
var that = this;//外部作用域的this对象保存在闭包能访问的变量里,that引用object
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());//my object

原创粉丝点击