javascript中作用域与关键字this

一.作用域

当代码在一个环境中执行时,会创建由变量对象构成的一个作用域链,其作用就是保证对执行环境有权访问的所有变量和函数的有序访问。标示符解析是沿着作用域链一级一级的搜索标示符过程,搜索过程从作用域链的前端开始,然后逐级的向后回溯,直到找到标示符为止。

-----------------------------------------------------------------------------------------------

1.常见基本作用域

var color='red';

function firstColor(){

    var aColor="blue";

    function bColor(){

        var xxColor=aColor;

        aColor=color;

    }

    bColor()

}

firstColor();

这里有三个执行环境:全局环境、firstColor和bColor两个局部环境,局部环境中的变量只能在当前环境中访问,但是能访问更高一层的环境,firstColor环境以及全局环境不能访问xxColor 但是bColor能访问全局以及firstColor环境。

-------------------------------------------------------------------------------------------------

2.不易理解的误区

var name="d";

function aa(){

    alert(name);

    var name='cc';

    alert(name);

}

aa();//underfind,cc;

分析:函数在执行时候先在内部作用域去寻找name的变量,由于函数执行是按照顺序执行,第一个alert时候name没有在aa函数找到就会向下接着找,在下面有name的定义,全局变量name=“d”但是执行第一个alert时候name只是就将该变量定义传给了第一个alert中的name,而该变量定义的值并没有传过去。相当于在第一个alert前面声明了一个变量name但是值没有定义。所以第一个alert出来的是underfind。假如替换成

var name="d";

function aa(){

    alert(name);

}

aa();//d

在函数执行时候 函数内部作用域找不到name定义,于是就去最近的作用域去找该变量的定义,此时外部变量就将变量以及值都传给了alert所以结果会是"d"。

------------------------------------------------------------------------------------------------

3.改变作用域

利用call或者apply方法(以call举例):

var name="aaa";

var object={name:"bbb"};

function sayName(){

    alert(this.name)

}

sayName();//aaa

sayName.call(object);//bbb

利用new实例化一个函数或者对象:

function changeName(name){
    this.name=name;

    this.sayName=function(){

        alert(this.name);

    }
}

如果直接changeName("dd").sayName()是会报错的,因为sayName此时是存在于windows全局的。

var newName=new changeName("xx");

newName.sayName()//xx

实例化一个对象(函数也是对象)就是讲构造函数(changeName)作用域赋给新对象(newName),此时this就指向了该新对象,而后在构造函数内为新对象创造属性,最后才返回newName新对象。

====================================================================

二.关键字this

书上说:“this对象是在运行时基于函数的执行环境绑定的”。也就是说单纯的this如果不调用则只代表一个符号,不代表任何对象,当调用时候才会产生一个内部对象,并且该对象的指针指向该实例(作用环境)。在全局函数中,this等于window,而当函数被作为某个对象的方法调用时候,this等于那个对象,匿名函数的执行环境具有全局性,因此this通常指向window(apply可以改变作用环境)

----------------------------------------------------------------------------------------------

var age="12";

var obj={

    age:"22",

    changeAge:function(){
        return function(){

            return this.age;

        }
    }

}

alert(obj.changeAge()())//12

每个函数在被调用时,其活动对象都会获得一个特殊变量this,内部函数在搜索这个变量时候只会搜索到其活动对象为止,因此永远不能直接访问外部函数中的this。这段代码中有一个匿名函数作为闭包想调用obj对象的age属性,而匿名函数活动对象只在changeAge内,因此this就指向了window,所以会输出的值为12.

两种方法可以改变此this作用域:

  1. 利用apply改变作用环境:

var age="12";

var obj={

    age:"22",

    changeAge:function(){
        return function(){

            return this.age;

        }.apply(this)
    }

}

alert(obj.changeAge())//22

这个时候应用apply在匿名函数并将匿名函数作用对象指向obj,此时的this.age就是22,该方式由于利用apply修改了匿名函数作用域,相当于被调用一次,所以匿名函数会被执行,因此在调用的时候就不用再去执行匿名函数了。

2.  将外部this保存为闭包能访问的变量:

var age="12";

var obj={

    age:"22",

    changeAge:function(){

        var that=this;

        return function(){            

            return that.age;

        };
    }

}

alert(obj.changeAge()())//22

这种方式在定义匿名函数之前,将this对象赋值给了一个名叫that的变量,而在定义了闭包之后,闭包也可以访问这个变量(因为它是我们在包含函数中特意声明的一个变量)即使在函数返回之后,that也仍然引用着obj,所以调用obj.changeAge()()也就返回了“22”

-----------------------------------------------------------------------------------------

this用处另一个地方就是js的面向对象以及继承过程中。this与作用域是无法分开的 在作用域的地方也提到了this;

var obj=function(){

        this.name="first";

        this.sayName=function(){

                alert(this.name)

        }

}

直接调用obj.sayName()会报错找不到sayName,原因是因为此时的name以及sayName()在实例化之前的this指针是指向window的.

如果直接调用window.sayName()会输出我们期望的结果。将其实例化之后再调用,var a=new obj();a.sayName()就没问题了。

obj.prototype.changeName=function(){ this.name="second"};

这里利用原型访问新建一个方法并改变原型中的name;

调用方法:

var a=new obj();

a.changeName();

alert(a.name)//"second";

delete a.name;

alert(a.name)//"first"

这里实例化原构造函数后,调用changeName相当于在实例函数对象中屏蔽了name的原始属性,而此属性只存在实例中,原型中的name属相并未改变。所以delete之后 a.name还是会顺着原型链找到构造函数中定义的name属性。

你可能感兴趣的:(js,web)