当前位置:文档之家› 作用域与闭包,js插件内部传递function()内部值

作用域与闭包,js插件内部传递function()内部值

《作用域与闭包:this,var,(function () {})》目标无具体目标知识点1.理解js 中var 的作用域2.了解闭包的概念3.理解this 的指向课程内容*es6中新增了let 关键词,与块级作用域,相关知识参考:/#docs/let *var 作用域先来看个简单的例子:var parent=function () {var name ="parent_name";var age =13;var child=function () {var name ="child_name";var childAge =0.3;// => child_name 13 0.3console.log(name, age, childAge);};child();// will throw Error// ReferenceError: childAge is not definedconsole.log(name, age, childAge);};parent();直觉地,内部函数可以访问外部函数的变量,外部不能访问内部函数的变量。

上面的例子中内部函数child 可以访问变量age,而外部函数parent 不可以访问child 中的变量childAge,因此会抛出没有定义变量的异常。

有个重要的事,如果忘记var,那么变量就被声明为全局变量了。

function foo() {value ="hello";}foo();console.log(value); // 输出hello console.log(global.value) // 输出hello这个例子可以很正常的输出hello,是因为value变量在定义时,没有使用var关键词,所以被定义成了全局变量。

在Node 中,全局变量会被定义在global对象下;在浏览器中,全局变量会被定义在window对象下。

如果你确实要定义一个全局变量的话,请显示地定义在global或者window对象上。

这类不小心定义全局变量的问题可以被jshint 检测出来,如果你使用sublime 编辑器的话,记得装一个SublimeLinter插件,这是插件支持多语言的语法错误检测,js 的检测是原生支持的。

JavaScript 中,变量的局部作用域是函数级别的。

不同于C 语言,在C 语言中,作用域是块级别的。

JavaScript 中没有块级作用域。

js 中,函数中声明的变量在整个函数中都有定义。

比如如下代码段,变量i 和value 虽然是在for 循环代码块中被定义,但在代码块外仍可以访问i 和value。

function foo() {for (var i =0; i <10; i++) {var value ="hello world";}console.log(i); //输出10console.log(value);//输出hello world}foo();所以有种说法是:应该提前声明函数中需要用到的变量,即,在函数体的顶部声明可能用到的变量,这样就可以避免出现一些奇奇怪怪怪的bug。

但我个人不喜欢遵守这一点,一般都是现用现声明的。

这类错误的检测交给jshint 来做就好了。

闭包闭包这个概念,在函数式编程里很常见,简单的说,就是使内部函数可以访问定义在外部函数中的变量。

假如我们要实现一系列的函数:add10,add20,它们的定义是int add10(int n)。

为此我们构造了一个名为adder 的构造器,如下:var adder=function (x) {var base = x;returnfunction (n) {return n + base;};};var add10 =adder(10);console.log(add10(5));var add20 =adder(20);console.log(add20(5));每次调用adder 时,adder 都会返回一个函数给我们。

我们传给adder 的值,会保存在一个名为base 的变量中。

由于返回的函数在其中引用了base 的值,于是base 的引用计数被+1。

当返回函数不被垃圾回收时,则base 也会一直存在。

我暂时想不出什么实用的例子来,如果想深入理解这块,可以看看这篇/articles/6731.html闭包的一个坑for (var i =0; i <5; i++) {setTimeout(function () {console.log(i);}, 5);}上面这个代码块会打印五个5出来,而我们预想的结果是打印0 1 2 3 4。

之所以会这样,是因为setTimeout 中的i 是对外层i 的引用。

当setTimeout 的代码被解释的时候,运行时只是记录了i 的引用,而不是值。

而当setTimeout 被触发时,五个setTimeout 中的i 同时被取值,由于它们都指向了外层的同一个i,而那个i 的值在迭代完成时为5,所以打印了五次5。

为了得到我们预想的结果,我们可以把i 赋值成一个局部的变量,从而摆脱外层迭代的影响。

for (var i =0; i <5; i++) {(function (idx) {setTimeout(function () {console.log(idx);}, 5);})(i);}this在函数执行时,this 总是指向调用该函数的对象。

要判断this 的指向,其实就是判断this 所在的函数属于谁。

在《javaScript语言精粹》这本书中,把this 出现的场景分为四类,简单的说就是:∙有对象就指向调用对象∙没调用对象就指向全局对象∙用new构造就指向新对象∙通过apply 或call 或bind 来改变this 的所指。

1)函数有所属对象时:指向所属对象函数有所属对象时,通常通过.表达式调用,这时this自然指向所属对象。

比如下面的例子:var myObject = {value:100};myObject.getValue=function () {console.log(this.value); // 输出 100// 输出 { value: 100, getValue: [Function] },// 其实就是 myObject 对象本身console.log(this);return this.value;};console.log(myObject.getValue()); // => 100getValue()属于对象myObject,并由myOjbect进行.调用,因此this指向对象myObject。

2) 函数没有所属对象:指向全局对象var myObject = {value:100};myObject.getValue=function () {var foo=function () {console.log(this.value) // => undefinedconsole.log(this);// 输出全局对象 global};foo();return this.value;};console.log(myObject.getValue()); // => 100在上述代码块中,foo函数虽然定义在getValue的函数体内,但实际上它既不属于getValue也不属于myObject。

foo并没有被绑定在任何对象上,所以当调用时,它的this指针指向了全局对象global。

据说这是个设计错误。

3)构造器中的this:指向新对象js 中,我们通过new关键词来调用构造函数,此时this 会绑定在该新对象上。

var SomeClass=function(){this.value=100;}var myCreate =new SomeClass();console.log(myCreate.value); // 输出100顺便说一句,在js 中,构造函数、普通函数、对象方法、闭包,这四者没有明确界线。

界线都在人的心中。

4) apply 和call 调用以及bind 绑定:指向绑定的对象apply() 方法接受两个参数第一个是函数运行的作用域,另外一个是一个参数数组(arguments)。

call() 方法第一个参数的意义与apply() 方法相同,只是其他的参数需要一个个列举出来。

简单来说,call 的方式更接近我们平时调用函数,而apply 需要我们传递Array 形式的数组给它。

它们是可以互相转换的。

var myObject = {value:100};var foo=function(){console.log(this);};foo(); // 全局变量 global foo.apply(myObject); // { value:100 }foo.call(myObject); // { value: 100 }var newFoo = foo.bind(myObject);newFoo(); // { value: 100 }完。

相关主题