JavaScript——函数

JavaScript——函数

一、函数的定义

定义一个函数:

方式一
function 函数名(参数){
	逻辑语句;
}

例如:绝对值函数

function abs(x){
    if(x>=0){
        return x;
    }else{
        return -x;
    }
}

一旦执行到 return 代表函数结束,返回结果!

如果没有执行 return ,函数执行完也会返回结果,结果就是 undefined

方式二
变量类型 函数名称 = function(参数){
	逻辑语句;
}
var abs = function(x){
    if(x>=0){
        return x;
    }else{
        return -x;
    }
}

function(x){ …. } 这是一个匿名函数。但是可以把结果赋值给 abs ,通过abs 就可以调用函数!

方式一和方式二等价!

二、调用函数

图1========================

在javaScript 函数中可以传任意个参数,也可以不传递参数,不会报错!

如何规避不存在的参数?

var abs = function(x){
    //手动抛出异常来判断
    if (typeof x!== 'number') {
        throw 'Not a Number';
    }
    if(x>=0){
        return x;
    }else{
        return -x;
    }
}

arguments

arguments是一个JS免费赠送的关键字,

代表,传递进来的所有的参数,是一个数组!

var abs = function(x){

    console.log("x=>"+x);

    for (var i = 0; i<arguments.length;i++){
        console.log(arguments[i]);
    }

    if(x>=0){
        return x;
    }else{
        return -x;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HkLJ5HWK-1580354791328)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130092526970.png)]

由上图就可以看出来,多个参数传递进去都是存在的,并且也都存储在arguments数组中!

问题: arguments 包含所有的参数,我们有时候想使用多余的参数来进行附加操作。需要排除已有参数,这种操作会带来弊端,为了解决这种弊端,ES6 引入了新特性(rest)。

rest

在未引入rest之前,获取除了已经定义的参数之外的所有参数使用下面的方法

if (arguments.length>2){
    for (var i = 2; i<arguments.length;i++){
		//...
    } 
} 

现在,

function aaa(a,b,...rest) {
    console.log("a=>"+a);
    console.log("b=>"+b);
    console.log(rest);
}

注意:rest 参数只能写在最后面,必须用 … 标识。

三、变量的作用域

function cm() {
    var x = 1;
    x = x + 1;
}
x = x + 2;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PTdAKKSW-1580354791329)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130094000198.png)]

报错了,这就说明,在javascript中, var 定义变量实际是有作用域的。

因此在函数体中声明的变量,在函数体外不可以使用。

function cm() {
    var x = 1;
    x = x + 1;
}

function cm2() {
    var x = 'A';
    x = x + 1;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eGitpTiI-1580354791330)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130095708613.png)]

以上运行结果说明,函数具有高度独立性!!!

function cm() {
    var x = 1;

    function cm2() {
        var y = x + 1; 
    }
}

!](https://img-blog.csdnimg.cn/20200130113305957.PNG)

没有报错,只是不存在返回值而已;

<script>
        function cm() {
            var x = 1;

            function cm2() {
                var y = x + 1;  // 2
            }

            var z = y + 1;
        }
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VvSGJM1q-1580354791331)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130095325705.png)]

此时报错了,说明内部函数可以访问外部函数的成员,反之则不行!

假设,内部函数变量和外部函数的变量重名

<script>
    function cm() {
        var x = 1;

        function cm2() {
            var x = 'A';
            console.log('inner'+x); 
        }
        console.log('outer'+x); 
    }
    cm();
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VoXkLCqC-1580354791332)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130100625247.png)]

<script>
    function cm() {
        var x = 1;

        function cm2() {
            var x = 'A';
            console.log('inner'+x); 
        }
        console.log('outer'+x);
        cm2();
    }
    cm();
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JJc0bfyw-1580354791332)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130100829556.png)]

因此,在JavaScript 中,函数查找变量是从自身函数开始,由 ‘’内‘’ 向 ‘’外‘’ 查找 。 假设外部存在这个同名的函数变量,则内部函数会屏蔽外部函数的变量!

提升变量的作用域

例一

<script>
    function cm() {
        var x = "x" + y;
        console.log(x);
        var y = 'y';
    }
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-irBI7PpU-1580354791332)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130101351833.png)]

例二

<script>
    function cm2() {
        var y;

        var x = "x" + y;
        console.log(x);
        y = 'y';
    }
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DL30I8QP-1580354791333)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130101619230.png)]

以上两个例子说明 ; js 执行引擎,自动提升了y的声明,但是不会提升变量y的赋值;

function cm() {
    var x = 1,
        y = x + 1,
        z,i,a; //undefined
    
    //之后可以随意对以上变量进行使用
}

养成规范: 所有的变量定义都放在函数的头部,不要乱放,以便于代码维护;

全局函数

  • 全局变量

    <script>
        var x = 1;
    
        function f() {
            console.log(x);
        }
        f();
        console.log(x);
    </script>
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cdcpuvy7-1580354791334)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130102241154.png)]

  • 全局对象window

    全局变量都会绑定在window下

<script>
    var x = 'xxx';
    alert(x);
    alert(window.x); // 默认所有的全局变量,都会自动绑定在 window对象下;
</script>

alert() 这个函数本身也是一个 window 变量;

<script>
        var x = 'xxx';

        window.alert(x);

 </script>

<script>

        var old_alert = window.alert;

        old_alert(x);

</script>

<script>

        var old_alert = window.alert;

        old_alert(x);

        window.alert = function () {

        };
       
        window.alert(123);

</script>

此时你会发现 alert() 失效了

<script>

        var old_alert = window.alert;

        old_alert(x);

        window.alert = function () {

        };
        // 发现 alert() 失效了
        window.alert(123);

        //恢复
        window.alert =  old_alert;
        window.alert(456);
</script>

以上测试说明:

Javascript 实际上只有一个全局作用域, 任何变量(函数也可以视为变量),假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域也没有找到,就会报错 RefrenceError(引用异常)。

如:

<script>

    window.alert(x);
    
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tFN5m7Wa-1580354791334)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130103731273.png)]

因此提出了JS中的规范。

规范

由于我们所有的全局变量都会绑定到我们的 window 上。如果不同的js 文件,使用了相同的全局变量,就会冲突如果能够减少冲突?

<script>
    // 唯一全局变量
    var cm = {};

    // 全部绑定到唯一的全局变量
    cm.name = 'kuangshen';
    cm.add = function (a,b) {
        return a + b;
    }
</script>

把自己的代码全部放入自己定义的唯一空间名字中, 以降低全局命名冲突的问题

正如jQuery一样

局部作用域 let

问题

<script>
    function aaa() {
        for (var i = 0; i < 3; i++) {
            console.log(i)
        }
        console.log(i+1); 
    }
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6KD3I57C-1580354791335)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130104530325.png)]

i 出了这个作用域还可以使用!!!

这和我们之前学的不一样呀,我们并不想让i 出了这个作用域还可以使用。于是ES6就引入了 let 关键字,解决局部作用域冲突问题!

此时

<script>
    function aaa() {
        for (let i = 0; i < 3; i++) {
            console.log(i)
        }
        console.log(i+1); 
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gJzoOUZC-1580354791335)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130104926583.png)]

以上便达到了我们的要求。

因此,建议大家都使用 let 去定义局部作用域的变量!

常量 const

在ES6 之前,定义常量采用强行洗脑方式,即:用全部大写字母命名的变量就是常量;建议不要修改这样的值。

var PI = '3.14';

console.log(PI);
PI = '213'; //其实是可以改变这个值的,只要不被洗脑
console.log(PI);

这样定义常量的方法一点都不严谨,也很滑稽。

为此, ES6 引入了常量关键字 const

<script>
    const PI = '3.14'; // 只读变量
    console.log(PI);
    PI = '123'; 
    console.log(PI);
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x7mhz2mx-1580354791336)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130105633079.png)]

这样定义常量的方法,就不会有被随意修改的风险了。

四、方法

方法的定义

方法:就是放在对象里面的函数。

对象只有两个东西 : 属性和方法。

<script>
    var person = {
        name: '张三',
        bitrh: 2000,
        // 方法
        age: function () {
            // 今年 - 出生的年
            var now = new Date().getFullYear();
            return now-this.bitrh;
        }
    }
    //属性
    console.log(person.name);
    //方法,一定要带 ()
    console.log(person.age());
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aoiFjakj-1580354791336)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130110530475.png)]

探讨:this.代表什么?

拆开上面的代码看看

function getAge() {
    // 今年 - 出生的年
    var now = new Date().getFullYear();
    return now-this.bitrh;
}

var person = {
    name: '张三',
    bitrh: 2000,
    age: getAge
}

console.log(person.name);
console.log(person.age());

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HhRLaLsn-1580354791336)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130111029005.png)]

此时的getAge()是window对象调用的,但是window对象并没有这个方法,因此结果为NaN。

这就更进一步说明了,明确对象的重要性(即,遵守规范的重要性)。

以上运行结果说明:this是无法指向的,是默认指向调用它的那个对象

apply()

在JS中,控制this指向的一种方法。

<script>
    function getAge() {
        // 今年 - 出生的年
        var now = new Date().getFullYear();
        return now-this.bitrh;
    }

    var person = {
        name: '张三',
        bitrh: 2000,
        age: getAge
    };

    var xiaoming = {
        name: '小明',
        bitrh: 2001,
        age: getAge
    };
    
    console.log(getAge.apply(xiaoming,[]));// this,指向了 xiaoming,参数为空

</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nt8aG1W3-1580354791336)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200130111921509.png)]

通过给apply()传递参数(其所指向的对象和所需的参数),控制this的指向,完成一定的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值