专栏首页前端之攻略js 函数作用域与this 的指向实例 原

js 函数作用域与this 的指向实例 原

函数的定义分为2种,(1)直接定义-window 下,内部定义;(2)对象的方法(或对象原型的方法),下面的函数fn1与fn2 是直接定义的函数, doFunction是对象定义的方法,这2种情况使用name时 name来自相应的域

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.onload = function() {
    resultCon = document.getElementById('result');
    //定义了局部的name变量跟全局的var name = "window 下的name <br/ >";是两个不同的变量,也就是说这个局部的name变量不会覆盖全局的变量,如果去掉var则会覆盖全局name变量的值
    var name = "onload下的name<br/>";
    var fn2 = function() {
        resultCon.innerHTML += name;
    };
    fn1();//输出window下的name,窗口加载完定义些变量后执行fn1,此时fn1里面的name是全局的
    fn2();//onload下的name,由于定义了name在onload下的局部变量
    var obj = new MyObj();
    obj.doFunction();//MyObj下的name ,实例化构造函数,在函数内部重新定义了name,所有会显示MyObj下的name
};
代码输出结果:
window下的name
onload下的name
MyObj下的name

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

var name = 'window下的name<br/>';
var resultCon;
function fn1() {
    resultCon.innerHTML += this.name;//直接定义的函数this指向window
}

function MyObj() {
    this.name = 'MyObj下的name<br/>';//或者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;// 直接定义的函数this指向window
    };
    fn1();//window下的name
    fn2();//window下的name
    var obj = new MyObj();
    obj.doFunction();//MyObj下的name
};
代码输出结果:
window下的name
window下的name
MyObj下的name

JS容易犯错的this和作用域

var someuser = { 
    name: 'byvoid', 
    func: function() {
        console.log(this.name); 
    }
}; 
var foo = { 
    name: 'foobar'
};
 
someuser.func(); // 输出 byvoid
 
foo.func = someuser.func; 
foo.func(); // 输出 foobar
 
name = 'global';
func = someuser.func; 
func(); // 输出 global

上面的解释:上面定义了2个对象someuser 与foo 以及一个全局变量name = 'global';一个对象的方法可以赋给另一个对象的方法,但是一个对象的属性值不会赋给另一个对象所有foo.func(); // 输出 foobar
var scope = 'top';
var f1 = function() { 
    console.log(scope);
};
f1(); // 输出 top
var f2 = function() { 
    var scope = 'f2'; 
    f1();
};
f2(); // 输出 top
上面解释:静态作用域的含义是函数作用域的嵌套关系由定义时决定而不是调用时决定,又称为词法作用域,函数f1在查找变量定义时,在语法分析时就已经完成,而不需要等到f1被调用的时候才开始
上面的例子如果增加var scope = 'top1';则f2(); // 输出 top1,因为f2()调用前就已经确定好语法分析scope = 'top1' 如下
var scope = 'top';
var f1 = function() { 
    console.log(scope);
};
f1(); // 输出 top
var scope = 'top1';
var f2 = function() { 
    var scope = 'f2'; 
    f1();
};
f2(); // 输出 top1
<script>
var scope="global";  
function t(){  
    console.log(scope);  //undefined 
    var scope="local"  
    console.log(scope);  //local 
}  
t();  
</script>

但是当去掉后面的 var scope="local" console.log(scope);惊奇的事情发生了
<script>
var a = "global";
function myFunction() {
	 console.log(a);  //global
} 
 myFunction();
</script>

//原因是由于变量提升拆解为下面的就好理解了
    function t() {
        var scope;
        console.log(scope);
        scope = "local";
        console.log(scope);
    }
    t()
var name="global";    
if(true){    
    var name="local";    
    console.log(name)    
}    
console.log(name);  

全部输出local因为if没有作用域,所以在if里面的var定义是重新定义了一个全局变量将前面的全局变量覆盖了
<script>
name="lwy";  
function t(){  
    var name="tlwy";  
    function s(){  
        var name="slwy";  
        console.log(name);  
    }  
    function ss(){  
        console.log(name);  
    }  
    s();  //slwy
    ss(); // tlwy
}  
t();   
</script> 
当执行s时,将创建函数s的执行环境(调用对象),并将该对象置于链表开头,然后将函数t的调用对象链接在之后,最后是全局对象。
然后从链表开头寻找变量name,很明显
name是"slwy"。
但执行ss()时,作用域链是: ss()->t()->window,所以name是”tlwy" 
var myvar = "my value";

(function() {
  console.log(myvar); // undefined  因为下面重新定义了局部变量,并且会变量提升, 相当于在console.log(myvar) 之前var myvar 如下:
  var myvar = "local value";
})();

var myvar = "my value";
(function() {
  var myvar;
  console.log(myvar); // undefined
  myvar = "local value";
})();


var myvar = "my value";
(function() {
  console.log(myvar); // my value  
  
})();

为创建的数组赋值 

function map() {
var a =	[0, 1, 2, 5, 10];  
 var result = []; // 创建一个新的数组
 var i;
  for (i = 0; i < a.length; i++)
    //var result = []; 不能放在此位置,因为每次循环时候result 都赋值为空
    result[i] = a[i]+2;
	alert(result);
	console.log(result);// 数组2,3,4,7,12
  return result;

}
function outside(x) {
  function inside(y) {
    return x + y;
  }
  return inside;
}

fn_inside = outside(3); 
result = fn_inside(5); 
console.log(result ) //8

arguments的用法 

function myConcat(separator) {
   var result = "", // initialize list
       i;
   // iterate through arguments
   for (i = 1; i < arguments.length; i++) {
      result += arguments[i] + separator;
      console.log(separator;)
//separator 接受的是第一个参数,(separator,separator1)若这样接受2个参数,separator形参接受的实参就是第一个参数,
   }
   return result;
}
你可以给这个函数传递任意数量的参数,它会将各个参数连接成一个字符串“列表”:

// returns "red, orange, blue, "
myConcat(", ", "red", "orange", "blue");
    var a = 20;
    var b = a;
    b = 30;
    console.log(a); //20
    var m = { a: 10, b: 20 };
    var n = m;
    n.a = 15;
    console.log(m.a); //15  对象是按引用访问的
var a = 20;
var obj = {
    a: 10,
    c: this.a + 20,
    fn: function() {
        return this.a
    }
}
console.log(obj.c); //40  由于c是属性不是方法,此时this指向window
console.log(obj.fn()); //10
var anotherobj = obj.fn;
console.log(anotherobj()); //20

(adsbygoogle = window.adsbygoogle || []).push({});

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • HTML5+APP 拍照压缩上传 原

    在拍照成功后会返回图片保存的路径,如上面的p参数,在压缩图片时要用到p,overwrite: true不能省略。

    tianyawhl
  • js实现千位分隔符 原

    \b      :用来匹配单词的边界,大小写字母、数字、下划线可以组成单词的字符,这些字符和其它字符相邻则为单词边界 如abcd@ , d与@之间就可以用\b...

    tianyawhl
  • 手机拍照预览2种实现方式 原

    手机拍照并把图片设定特定尺寸,在网上找了一些资料,可以使用html5原生的方式 也可以使用插件,现在分别按2种方式实现

    tianyawhl
  • 重读《JavaScript高级程序设计》

    ECMAScript 函数不能像传统意义上那样实现重载。而在其他语言(如Java)中,可以为一个函数编写两个定义,只要这两个定义的签名(接受的参数类型和数量)不...

    嘉明
  • 【一起来烧脑】一步学会TypeScript入门

    字符串新特性 变量和参数新特性 函数新特性 匿名函数 for of循环 TypeScript语言中的面向对象特性

    达达前端
  • 「查缺补漏」送你 54 道 JavaScript 面试题

    看过源码的同学应该知道,filter源码中,会去判断数组的这个索引值是不是数组的一个属性,有兴趣的同学可以看看我写的这篇关于数组的:[干货?]从详细操作js数组...

    童欧巴
  • ECMAScript 6介绍

    js中并没有声明常量的关键字,在es6中,出现了可以声明常量的关键字,const

    一个淡定的打工菜鸟
  • node+express使用multiparty实现文件上传

    文件上传在一个项目中是相对于比较基础的功能,今天分享一下自己是如何在nodejs中使用中间件multiparty实现文件上传的。nodejs环境的搭建就不赘述了...

    算法与编程之美
  • php下的原生ajax请求用法实例分析

    浏览器中为我们提供了一个JS对象XMLHttpRequet,它可以帮助我们发送HTTP请求,并接受服务端的响应。

    砸漏
  • ES6新特性概览

    前言 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得JavaScript语言...

    laixiangran

扫码关注云+社区

领取腾讯云代金券