js函数的作用域与this指向

一、变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
  函数体内有var申明的变量,则只能调用函数体内的变量,没有局部变量才能调用父级函数的变量
函数体内申明变量时若没有var 则相当于申明了一个顶层的全局变量

  学习地址:http://blog.csdn.net/yueguanghaidao/article/details/9568071

     

函数体内没有局部变量 实例如下:

 var scope='global';

function t(){
     console.log(scope);       //global 函数t内没有局部变量scope所以调用父级作用域内的变量scope
     scope='local';                  //改变全局scope=local
     console.log(scope);      //local
}
t();
console.log(scope);     //local 全局变量已被改


函数体内有var申明的局部变量 实例如下:

var scope='global';
function t(){
        console.log(scope); //函数体内有局部变量 预解析时局部scope=undefined;
        var scope='local'; //局部scope=local
        console.log(scope); //local
}
t();


当函数申明时有参数时,相当于定义了函数体内的局部变量

var scope='global';
function t(scope){                       //参数scope相当于定义了函数体内的局部变量
       console.log(scope);            //undefined
       scope='local';
       console.log(scope);          //local
}
t();


二、函数作用域的嵌套关系是定义时决定的,而不是调用时决定的,也就 是说,JavaScript 的作用域是静态作用域,又叫词法作用域,这是因为作用域的嵌套关系可 以在语法分析时确定,而不必等到运行时确定


var scope='global';
var f1=function(){
       console.log(scope);
}
f1();
var f2=function(){
       var scope='f2';
       f1();
}
f2();


三、例子参悟


var name='window下的name<br/>';
var resultCon;
function fn1(){
       resultCon.innerHTML+=name;
}

function MyObj(){
       var name='myObj下的name<br/>';
       this.doFunction=function(){
              resultCon.innerHTML+=name;
       }
}


window.οnlοad=function(){
       resultCon=document.getElementById('result');
       var name='onload下的name<br/>';
       var fn2=function(){
       resultCon.innerHTML+=name;
}
fn1();     //window下的name
fn2();     //onload下的name
var obj=new MyObj();
       obj.doFunction();       //myObj下的name
}



在使用name的值时将“name”用“this.name”来代替会出现什么情况呢,看下例:

var name='window下的name<br/>';
var resultCon;
function fn1(){
       resultCon.innerHTML+=this.name;
}
function MyObj(){
       var name='myObj下的name<br/>';
       this.doFunction=function(){
              resultCon.innerHTML+=this.name;
       }
}


window.οnlοad=function(){
       resultCon=document.getElementById('result');
       var name='onload下的name<br/>';
       var fn2=function(){
              resultCon.innerHTML+=this.name;
       }
       fn1();   //window下的name
       fn2();   //window下的name
       var obj=new MyObj();
       obj.doFunction(); //this指向实例 undefined
}


以上实例从结果来看可以看出

对于直接定义的函数,this指向window。

对于对象的方法,this指向实例化对象(对应于实例化对象默认返回this的情况)。

也可以看到this和作用域是两套分离的链,遵循个自的变量查询逻辑,具体的查询逻辑在下面的性能分析中会提到。

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

var name = 'window下的name<br/>';
var resultCon;
function fn1() {
           resultCon.innerHTML += this.name;
}


function MyObj() {
    var name = 'MyObj下的name<br/>';
    this.doFunction = function() {
        resultCon.innerHTML += this.name;
    };
}


window.onload = function() {
    resultCon = document.getElementById('result');
    var name = "onload下的name<br/>";
    var fn2 = function() {
        resultCon.innerHTML += this.name;
    };
    var myThis = {
        name: "自定义的this的name属性<br/>"
    };
    fn1.call(myThis);//自定义的this的name属性
    fn2.call(myThis);//自定义的this的name属性
    var obj = new MyObj();
    obj.doFunction.call(myThis);//自定义的this的name属性
};

用call/apply改变方法的this指向, 调用时call和apply的使用是为了改变被调用函数的this指向。with的使用是为了改变被调用函数中变量的查询域。

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


var name = 'window下的name<br/>';
var resultCon;
function fn1(myScope) {
    with (myScope) {
        resultCon.innerHTML += name;
    }
}


function MyObj(myScope) {
    var name = 'MyObj下的name<br/>';
    
    this.doFunction = function(myScope) {
        with (myScope) {
            resultCon.innerHTML += name;
        }
    };
}




window.onload = function() {
    resultCon = document.getElementById('result');
    var name = "onload下的name<br/>";
    var fn2 = function(myScope) {
        with (myScope) {
            resultCon.innerHTML += name;
        }
    };
    var myScope = {
        name : "自定义变量查询域</br>"
    };


    fn1(myScope);//自定义变量查询域
    fn2(myScope);//自定义变量查询域
    var obj = new MyObj();
    obj.doFunction(myScope);//自定义变量查询域
    
};


看到with的使用并不方便,需要在被调用函数中添加with,有人可能想能不能向下面那样调用来整体改变变量作用域而不去改变被调用函数呢?


with (myScope) {
    fn1();
    fn2();
    var obj = new MyObj();
    obj.doFunction();
}


很遗憾,不可以!所以在一些成熟的框架中随处可见call和apply的使用,却很少用到with,在用JSHint检测js语法的时候with处都标了小红点,在一些js编码指导中也建议尽量少用with,因为with改变了变量的默认查询链,所以会给后期的维护人员一些困惑,还有性能方面的一些考虑,请慎用with。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值