万物皆对象
一 什么是函数
1 函数就是可以执行的代码块这个比较好理解 就是在一个大括弧里定义一段代码,封装了一系列逻辑操作,
然后输入参数 调用函数(代码块) 返回处理结果 函数都是这么一个结果。
2 函数可以通过函数声明和表达式两种定义方式
这两种函数表示方法看起来差不多 但是是有一点差别的,函数声明会被提升到是上下文的顶部,上下文是什么东西:要么是 该函数被声明是所处的函数的范围,要么是全局范围的 这是可见性的问题后面的的文章可能会详细介绍
function myfunction (arg) {
return arg+'函数声明';
}
var myfunction = function(arg) {
return arg+'函数表达式';
}
例子:function myfunction (arg) {
console.log(arg+'函数声明') ;
}
var myfunction2=myfunction;
myfunction2('test')
function myfunction (arg) {
console.log(arg+'函数声明2') ;
}
myfunction2('test')
你觉得两次运行下面的函数会有什么结果
myfunction2('test')
结果:
test函数声明2
解释:这看出来js引擎对函数声明并不是一边运行,一边解析的 而是同意将函数声明的函数提升到上下文的顶部(相当于在先在顶部定义了myfunction函数 但由于我定义两次 所以后者把前者覆盖了。)至于为什么重新定义myfunction函数会影响到myfunction2呢 ,因为myfunction2=myfunction这句话只是将myfunction函数的引用赋值而已 ,myfunction2这个引用最后也是指向的值还是myfunction函数,所以myfunction函数改变 ,myfunction2指向的内容自然改变。
test函数声明2
解释:这个不用解释
这就是一个js区别于其他语言的一个很有意思的一个特性
首先我们知道函数也是一个对象,你可以像使用对象一样使用函数,
可以把函数当成变量赋值, 甚至可以把其当成参数传递给别的函数或许作为函数的返回值 基本上可以使用引用值的地方都 可以使用函数,
这意味着函数威力无穷 灵活多变 但是 我们了解函数即对象之后 它的很多特性就很容易解释得通。
二 怎么调用函数
1 仅仅作为函数调用(待会解释)
当我们通过表达式后声名定义函数后调用 例子:
function a(){}; a(); //作为函数调用
2 作为对象的属性调用
定义一个对象,函数作为其中的属性值,则是对象属性调用 例子:
var obj={
myfunc:function(){}
}
obj.myfunc();
3 call apply方法调用
call方法和apply方法其实差不多,都是改变函数内部this值的一种手段,只是用的时候,需要的参数不一样而已。
三 函数调用js引擎做的工作
当一个函数被调用的时候,js引擎其实不止只是为函数准备了好参数以供函数体调用,还有就是准备了arguments,this这两个默认参数,所以
function myfunc(){
console.log(this)
console.log(arguments)
} //打印出两个对象
调用函数的时候我们没有传这两个this arguments 参数 ,但是却能打印出来,这是因为这是js引擎默认传递的。问题来了,默认传递的这俩有啥用?
arguments: js的独特之处在于你可以给函数传递任意数量的参数却不造成错误 例子:
定义
function myfunc(a,b,c){
console.log(a)
console.log(b)
console.log(c)
}
调用
myfunc(); 输出 undefined undefined undefined
myfunc('fd') 输出 fd undefined undefined
myfunc(3,5,5,2) 3 5 5
以上的调用都不会出错 无论你调用时传递的参数的实际数量少于或多余声名时的数量。
从上面看出 当实际传递的参数少于形式参数时,没有接受的实际参数的参数会被自动赋予undefined,当实际传递的参数多于形式参数时,多余的参数会被遗弃,js引擎不会进行处理。所以引擎是怎么做到的?
其实就是靠着 arguments参数的作用 ,arguments是一个类似数组的一个对象。但那不是数组 ,虽然可以像数组通过过下标寻找成员,也有length属性,但真的不是数组;通过Array.isArray(arguments)永远返回false。
arguments对象以键值对的对象方式保留着实际参数 类似于
{ '0': arg, 注意是实际参数
'1': arg2
}
所以我们可以通过arguments[index]来获取参数 arguments.length获取实际参数的个数。
所以
function test(){
return arguments[0];
}
console.log(test.length) //打印形参个数 返回0
console.log(test(5)) // 打印实参 返回5 所以实际传递参数是不会对函数调用产生任何问题,所以有人问,如果arguments可以直接访问实际参数, 那为什么还要这些命名参数(定义函数是写下的参数名字) 答案很简单---因为方便呐,你想想每次你写函数体的时候都要arguments[0]来访问参数吗?而且有参数名字好记!
this:this是一个对象 每个函数作用域内都有一个this对象代表调用该函数的对象。在全局作用中,this表示全局变量。当一个函数被调用,默认this的值等于那个对象;
所以默认情况下引擎传递的this是默认的;但是我们可以通过call或apply改变默认this,强制制定this的值 例子
var obj={
name:'djfk',
callname:myfunc
}
function myfunc(a){
console.log(this)
console.log(a)
}
myfunc.call(obj,'dfd')强制制定myfunc函数调用时的this的值为obj
输出
{ name: 'djfk', callname: [Function: myfunc] }
dfd
未完 待续。。。。。。