JavaScript 函数

一.函数
1.定义Function对象:

  • Function类可以表示开发者定义的任何函数
  • 虽然由于字符串的关系,第二种创建方式写起来有些困难,但有助于理解函数只不过是一种引用类型,它们的行为与用 Function类明确创建的函数行为是相同的
  • js的函数加载执行与python不同:整体加载完才会执行,所以在函数声明上/下执行函数都可以
//用Function类直接创建函数的语法:
1.function 函数名 (参数){
函数体;
    return 返回值;
}

alert(1);
function func1(){
    alert('hello yuan!');
    return 8
}
ret=func1();
alert(ret)

2.var 函数名=new Function('参数1'...'参数n','function_body');

var func1=new Function("name","alert(\"hello\"+name);")
func1("yuan")

<script>
    //f();----->OK
    function f(){
        console.log("hello")
    }
    f()//----->OK
</script>

2.功能说明:

·可以使用变量,常量,表达式作为函数调用的参数
·函数由关键字function定义
·函数名的定义规则与标识符一致,大小写是敏感的
·返回值必须使用return

3.Function对象的属性

length:声明了函数期望的参数个数
function fun1(a) {return a}
alert(func1.length)//1

4.Function对象的方法
valueOf()参见:https://www.cnblogs.com/fengweb/p/5755052.html
toString()参见:https://www.cnblogs.com/czhyuwj/p/5895766.html

//也有与所有对象共享的valueOf()方法和toString()方法
//返回的都是函数的源代码,在调试时尤其有用
func1.valueOf();
fun1.toString();

运算符void():拦截方法的返回值
alert(void(fun1(1,2)))

5.函数的调用

function func1(a,b){
    alert(a+b);
}
    func1(1,2);//3
    func1(1,2,3);//3--->取前2个
    func1(1);//NaN--->第二个参数传入undefined
    func1();//NaN--->两个参数均传入undefined
    fun1('hello','world');//helloworldundefined
    //只要函数名写对即可,参数怎么填都不报错.

 function a(a,b){
    alert(a+b);
}
   var a=1;
   var b=2;
   a(a,b)//报错:a is not a function

6.函数的内置对象arguments:集成在函数中,所有传入的参数构成1个arguments对象

function add(a,b){
        console.log(a+b);//3
        console.log(arguments.length);//2
        console.log(arguments);//1个arguments对象(见下图)
    }
add(1,2)
//用处1:
function nxAdd(){
    var result=0;
    for (var num in arguments){
        result+=arguments[num]
    }
    alert(result)
}
nxAdd(1,2,3,4,5)
//用处2:
function f(a,b,c){
    if (arguments.length!=3){
        throw new Error("function f called with"+arguments.length+" arguments,but it just need 3 arguments")
    }
    else {
        alert("success!")
    }
}
f(1,2,3,4,5)

在这里插入图片描述
7.匿名函数

//func('hello')//报错,匿名函数不加载
var func = function(arg){
    alert(arg);
}
func('hello')//hello
//这不是一个标准的函数,是一个匿名函数,赋给func

//匿名函数的应用
(function(){
    alert("tony");
} )()
(function(arg){
    console.log(arg);
})('123')

8.自执行函数:创建并执行函数

(function [<func>]([<param1>...]) {<command>})()

//实例:
(function inner() {
    console.log(this);
})()
//相当于:
function inner() {
    console.log(this);
}
inner()

二.函数的作用域链和闭包
1.作用域

  • js的作用域和py相似,if/while等控制语句没有自己的作用域,而函数有自己的作用域:
if(1==1){
    var s=12;
}
console.log(s);//12

function f(){
    var temp=666;
    console.log(temp)
}
f();//666
console.log(temp);//报错:Uncaught ReferenceError: temp is not defined
  • 嵌套函数的作用域:
var city = 'beijing';
function func(){
    var city = 'shanghai';
    function inner(){
        var city = 'shenzhen';
        console.log(city);
    }
    inner();
}
func();//shenzhen
var city = 'beijing';
function Bar(){
    console.log(city);
}
function func(){
    var city = 'shanghai';
    return Bar;
}
var ret = func();
ret();//beijing
  • 作用域是在执行前创建的:
var v=123;
function foo() {
    var v=456;
    function inner() {
        console.log(v);//无论在哪里执行,都输出456
    }
    return inner
}
result=foo()
console.log(result())

2.闭包

var city = 'beijing';
function func(){
    var city = "shanghai";
    function inner(){
        //var city = "langfang";
        console.log(city);
    }
    return inner;
}
var ret = func();
ret();//shanghai
var city = 'beijing';
function func(){
    var city = "shanghai";
    function inner(){
        //var city = "langfang";
        console.log(city);
    }
    return inner;
}
var ret = func();
ret();//shanghai
var city = 'beijing';
function Bar(){
    console.log(city);
}
function func(){
    var city = 'shanghai';
    return Bar;
}
var ret = func();
ret();//beijing

3.作用域链(Scope Chain):

  • 在JS中,函数也是对象,实际上,JS里一切都是对象;函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JS引擎访问的内部属性;其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问
var x=1;
function foo() {
    var y = 2;
    function bar() {
        var z = 3;
    }
}
#bar的作用域链: barScopeChain=[bar.AO, foo.AO, global.VO];
#foo的作用域链: fooScopeChain=[foo.Ao, global.VO];
AO,VO:
    在函数创建时,每个函数都会创建1个活动对象Active Object(AO)全局对象为Global Object(VO)
    创建函数的过程也就是为这个对象添加属性的过程,作用域链就是由这些绑定了属性的活动对象构成的
    例如:寻找x变量,bar()在搜寻变量x的过程中,先从自身AO对象上找
    如果bar.AO存在这个属性,则会直接使用这个属性的值
    如果不存在,则会转到父级函数的AO对象,也就是foo.AO
    如果找到x属性则使用,找不到继续在global.VO对象查找,找到x的属性,返回属性值
    如果在global.VO中没有找到,则会抛出异常ReferenceError

执行上下文:
    函数在执行时会创建1个称为"执行上下文"(execution context)的内部对象,该对象定义了函数执行时的环境
    每个执行上下文都有自己的作用域链,用于标识符解析,当执行上下文被创建时
    它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象

函数执行:
    在函数执行过程中,每遇到1个变量,都会检索从哪里获取和存储数据
    该过程从作用域链头部(即活动对象)开始搜索,查找同名的标识符
    如果找到了就使用这个标识符对应的变量,如果没有则继续搜索作用域链中的下一个对象
    如果搜索完所有对象都未找到,则认为该标识符未定义,函数执行过程中,每个标识符都要经历这样的搜索过程
  • 创建作用域链的过程:
//函数进入全局,创建VO对象,绑定x属性<入栈>
global.VO={x=underfind; foo:reference of function}
//这里只是预解析,为AO对象绑定声明的属性
//函数执行时才会执行赋值语句,所以值是underfind

//遇到foo函数,创建foo.AO,绑定y属性<入栈>
foo.AO={y=underfind, bar:reference of function}

//遇到bar函数,创建bar.AO,绑定z属性<入栈>
bar.AO={z:underfind}
//作用域链和执行上下文都会保存在堆栈中,所以:
//bar函数的scope chain为:
[0]bar.AO-->[1]foo.AO-->[2]global.VO

//foo函数的scope chain为:
[0]foo.AO-->[1]global.Vo
//建议:少定义全局变量
//理由:因为作用域链是栈的结构,全局变量在栈底
//每次访问全局变量都会遍历一次栈,这样会影响效率
  • 函数的scope等于自身的AO对象加上父级的scope,也可以理解为一个函数的作用域等于自身活动对象加上父级作用域
  • 函数执行前后的作用域链:
    在这里插入图片描述
    在这里插入图片描述
  • 作用域链的非自己部分在函数对象被建立(函数声明,函数表达式)的时候建立,而不需要等到执行
for (var i=1; i<=9; i++) {
    setTimeout( function timer(){
    console.log( i );
    },1000 );
}

for (var i=1; i<=9; i++) {
    (function(){
        var j = i;
        setTimeout(function timer(){
            console.log( j );
    },1000);
})();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值