5 全局函数的调用
调用全局函数,被编译成为了如下的语句
那么此时在fn内部的this就成为了global!!!
首先,要了解一点关于Function的前置知识才能理解。
【以下节选自w3school】
ECMAScript 的函数实际上是功能完整的对象。
Function 对象(类)
ECMAScript 最令人感兴趣的可能莫过于函数实际上是功能完整的对象。
Function 类可以表示开发者定义的任何函数。
用 Function 类直接创建函数的语法如下:
var function_name = new function(arg1, arg2, ..., argN, function_body)
在上面的形式中,每个 arg 都是一个参数,最后一个参数是函数主体(要执行的代码)。这些参数必须是字符串。
记得下面这个函数吗?
function sayHi(sName, sMessage) {alert("Hello " + sName + sMessage)
}
还可以这样定义它:
var sayHi = new Function("sName", "sMessage", "alert(\"Hello \" + sName + sMessage)")虽然由于字符串的关系,这种形式写起来有些困难,但有助于理解函数只不过是一种引用类型,它们的行为与用 Function 类明确创建的函数行为是相同的。
请看下面这个例子:
function doAdd(iNum) {alert(iNum + 20)
}
function doAdd(iNum) {
alert(iNum + 10)
}
doAdd(10)//输出 "20"
如你所知,第二个函数重载了第一个函数,使 doAdd(10) 输出了 "20",而不是 "30"。
如果以下面的形式重写该代码块,这个概念就清楚了:
var doAdd = new Function("iNum", "alert(iNum + 20)")
var doAdd = new Function("iNum", "alert(iNum + 10)")
doAdd(10)
请观察这段代码,很显然,doAdd 的值被改成了指向不同对象的指针。函数名只是指向函数对象的引用值,行为就像其他对象一样。甚至可以使两个变量指向同一个函数:
var doAdd = new Function("iNum", "alert(iNum + 10)")var alsodoAdd = doAdd
doAdd(10) //输出 "20"
alsodoAdd(10) //输出 "20"
在这里,变量 doAdd 被定义为函数,然后 alsodoAdd 被声明为指向同一个函数的指针。用这两个变量都可以执行该函数的代码,并输出相同的结果 - "20"。因此,如果函数名只是指向函数的变量,那么可以把函数作为参数传递给另一个函数吗?回答是肯定的!
function callAnotherFunc(fnFunction, vArgument) {fnFunction(vArgument)
}
var doAdd = new Function("iNum", "alert(iNum + 10)")
callAnotherFunc(doAdd, 10)//输出 "20"
在上面的例子中,callAnotherFunc() 有两个参数 - 要调用的函数和传递给该函数的参数。这段代码把 doAdd() 传递给 callAnotherFunc() 函数,参数是 10,输出 "20"。
注意:尽管可以使用 Function 构造函数创建函数,但最好不要使用它,因为用它定义函数比用传统方式要慢得多。不过,所有函数都应看作 Function 类的实例。
Function 对象的 length 属性
如前所述,函数属于引用类型,所以它们也有属性和方法。
ECMAScript 定义的属性 length 声明了函数期望的参数个数。例如:
function doAdd(iNum) {alert(iNum + 10)
}
function sayHi() {
alert("Hi")
}
alert(doAdd.length) //输出 "1"
alert(sayHi.length) //输出 "0"
函数 doAdd() 定义了一个参数,因此它的 length 是 1;sayHi() 没有定义参数,所以 length 是 0。
Function 对象的方法
Function 对象也有与所有对象共享的 valueOf() 方法和 toString() 方法。这两个方法返回的都是函数的源代码,在调试时尤其有用。例如:
function doAdd(iNum) {alert(iNum + 10)
}
document.write(doAdd.toString())
【解析】:
var Fn = Function, //这一句将Fn设定为Function对象的引用;
global = (new Fn("return this"))()//创建了一个新的Function对象,并将运行结果赋予global变量
其实只要不是在function中使用定义的变量均会被看做window的成员处理,所以其实var global的时候global已经是window的成员,后面无论赋任何值给它,它都是window对象的成员。
面向对象编程中,我们经常要和this打交道。而对于函数中this到底指向哪里,对刚开始接触JavaScript的我们,经常会分不清楚。
我们必须明确的是函数中this的指向 不是固定 的,和函数执行时的环境有关,简单的说,我们可以理解函数中this指向的是 当前调用该函数的对象 ,所以我们也针对以下几种情况来消化下这种说话。
1、作为函数调用时
简单的例子如下:
在浏览器时执行该代码时,打印出来的都是window对象。
因为作为函数调用时,默认是被认为在全局对象中调用该函数(nodejs环境中是global对象) 注:不是在当前函数所处的作用域对象
有一点需要注意的是, 箭头函数 (我们等等再特殊讲下)
2、作为对象方法调用时
简单的例子如下
代码执行时,答应出来的是obj对象,name值是obj,这是满足我们的预期:函数目前就是作为obj的方法被调用,所以调用该函数的对象是obj。
这种情况我们很容易消化,但是换了一种情况就另当别论,如
这个时候打印出来的window对象,name值是test[what][what]
原来这个时候fn指向的是一个函数 (不是指向 obj执行logThis 这个行为) ,fn调用就是调用一个函数,也就是第一种情况,所以上面的例子就如下:
3、作为构造函数执行
简单的例子如下
这个时候打印出来的是我们新生成的people对象。
因为构造函数执行的过程我们可以简单理解为
1、新生成一个对象(people)
2、该对象原型对象指向构造函数的prototype对象(People.prototype)
3、通过新生成的对象调用构造函数(可以简单理解为People.call(this))
4、作为箭头函数调用
简单例子如下
这个时候打印的我们可能因为都是window对象,然而结果打脸了,第一个打印的是window对象,第二个打印的是obj对象[发怒]
原来箭头函数, 不会生成新的this指向 ,箭头函数在哪个环境执行,指向的就是当前环境的this对象,也就是第二种情况下,this指向的obj.logThis()执行时的this指向(前面我们提到的是obj对象)
5、apply,call,bind调用
this的指针默认指向就是上面提到的4种,但是总有需求,我们想要自定义this指向,这个时候apply,call,bind这3个方法就排的上用场
这三个方法都是函数对象自身的方法,第一个参数支持传入的是函数调用时设置的this对象,如
这个时候第一个打印的是window对象(看1说明),第二个打印的是obj对象(我们通过传参的方法明确说明函数执行是的this对象是obj)
而这三个方法,不同如下
上述总结希望对大家有用[作揖]