前端学习之路-函数

JavaScript函数

函数是这样的一段javascript代码,它只定义一次,点可能被执行或调用任意次。

变量提升

在js代码编译的过程中,js引擎将会将所有的变量拿出来初始化

比如说

console.log(c);var c=1
undefined
undefined

console.log(b);var b=1

undefined
undefined

console.log(a);let a=1

VM144:1 Uncaught ReferenceError: a is not defined
at <anonymous>:1:13

在声明变量声明之前打印此变量就会被js附上默认值undefined

并且这个行为恰恰反应一个道理 变量提升

等到执行到a=1才会重新赋值

什么是函数

特定功能的代码集合

定义函数方式

1.函数声明
            // -1).函数的声明(直接通过function 函数名(){...}的形式来定义函数)
            foo();// 打印 window foo ...
            function foo() {
                console.log("window foo ...");
            }
            foo();// 打印 window foo ...
2.函数表达式
 // -2).函数表达式
            fun();// 报错 fun is not defined ...
            let fun = function() {
                console.log("window fun ...");
            };
————————————————

为什么会有这个现象呢?

因为foo这种函数的声明的方式创建的函数会存在变量提升,即在编译的时候会先将foo整个函数放到执行环境中去进行初始化,所以foo函数体是先foo()执行的,所以不会报错且能正常执行。

但是fun属于函数表达式方式创建的函数,其变量提升的时候不是提升的整个函数,而是将变量**fun进行初始化即为其开辟空间赋默认值undefined,**带到代码执行到赋值号(=)的时候,才会将其后面的函数初始化并将函数的指针赋值给fun变量,所以函数是后于fun();执行的,所以你先去执行fun()肯定会报错fun is not defined …

但是如果你将执行语句放在函数定义的下面执行就会正常执行,因为此时fun已被真正赋值 …

3构造器声明
let constructor = new Function("num1", "num2", "console.log('ok');console.log('sum:' + (num1 + num2))");
            constructor(1, 2);// 打印 ok sum:3

函数调用

函数声明后需要通过调用才能被执行。JavaScript中通常有4种方式来调用函数:

  • 作为普通函数;
  • 作为对象方法;
  • 作为构造函数;
  • 通过它们的call()apply()方法间接调用。

JS作用域

var arg = "a";
        console.log(arg);// 打印 a
        function foo() {
            var arg = "b";
            console.log(arg);// 打印 b
        }
 foo();
function f(){
	
}

函数嵌套

function hy(a,b){
	function sq(x){return x*x}
	return Math.part(sq(a)*sq(b))
}

可以访问包含自己的函数参数

函数它也有全局函数和局部函数

函数返回值

首先要注意在JavaScript中不管我们指定还是没有指定函数返回值,函数都会返回一个值

如果是没有指定 undefined

如果指定 返回指定的值

let res_1 = function back1() {
            return "1";
        };
        console.log(res_1());// 打印 1
 
        let res_2 = function back2() {
 
        };
        console.log(res_2());// 打印 undefined

注意情况

 !function f() {
            return console.log(1),
                console.log(2)
  }()
  1,2

函数的参数传递

关键词解释
  • 参数(行参:函数中定义的变量;实参:调用函数时传入的参数);
  • 调用上下文:普通函数——this(对象调用,this则为方法上级的对象;直接调用,为window)
//exam 2
var obj={
    a:1,
    b:2,
    c:{
        a:3,
        fn:()=>{
            console.log(this.a)
        },
        fn2:function(){
            console.log(this.a)
        }
    }
}
var a =4
obj.c.fn()    //4
obj.c.fn2()   //3
 // 函数作为对象也可以当做实参传给其它函数
            function eat(food) {
                return `吃:${food}`;
            }
            person("苹果", eat);
            function person(food, eat) {
                console.log(`${eat(food)}`);// 打印 人吃:苹果
            }

注意:如果存在形参,但并没有传递实参怎么办

第一种写法

 // ES5及其之前的默认值设置
            function defaultValue(x, y) {
                if(typeof y === 'undefined' || Number.isNaN(Number(y))) {
                    y = 2;
                }
                y = Number(y);
                return x + y;
            }
        console.log(defaultValue(1));

第二种写法

function defaultValue(x, y = 2) {
            return x + y;
        }
        console.log(defaultValue(1));

注意

但是这种函数写法 不存在 函数length 不能加到 length 的长度上

  // -1).length属性 -> 函数形参非设置默认值的参数个数
            function sleep(arg_1, arg_2, arg_3 = 3) {
                console.log(`${arg_1}只羊,${arg_2}只羊,${arg_3}只羊`);// 打印 1只羊,2只羊,3只羊
                console.log(`函数参数的长度(不包括设置默认值的参数个数):${sleep.length}`);// 打印 函数参数的长度(不包括设置默认值的参数个数):2
            }
            sleep(1, 2);
arguments对象

存储当前的函数里面传递进来的实参

是一个类数组用来访问形参

 function watch() {
                console.log(`我是数组吗?${arguments instanceof Array}`);// 打印 我是数组吗?false
                console.log(`arguments的长度:${arguments.length},第一个参数为:${arguments[0]}`);// 打印 arguments的长度:3,第一个参数为:电视剧
            }
            watch("电视剧", "电影", "动漫");

instanceof 运算符只能用作对象的判断

this

.this谁调用我所在的方法,我就指向谁

总而言之记住一句话:谁调用我所在的方法,我就指向谁!

全局作用域执行,调用者是window

new构造器创建对象执行 调用者就是new的对象

如果是dom的事件绑定 指向的改DOM元素

严格模式下:

 // -1).场景一:普通函数
                function walk() {
                    console.log(`walk this指向了:${this}`);// 打印 walk this指向了:undefined
                }
                walk();

非严格模式:

  // -1).场景一:普通函数
        function walk() {
            console.log(`walk this指向了:${this}`);// 打印 walk this指向了:window
        }
        walk();

构造函数

 function run(address, speed) {
                    this.address = address;
                    this.speed = speed;
                    this.sayThis = function() {
                        console.log(`run this指向了:${this},this是否指向构造器的外部实例${this === obj},地址:${this.address},速度:${this.speed}`);// 打印 run this指向了:[object Object],this是否指向构造器的外部实例true,地址:承德市,速度:20
                    }
                }
                let obj = new run("承德市", 20);
                obj.sayThis();

事件绑定

 // -3).场景三:事件绑定
   let btn = document.getElementsByTagName("button")[0];
                btn.addEventListener('click', function() {
                    console.log(`this指向:${this}`);// 打印 this指向:[object HTMLButtonElement]
                    console.log("this"+this.value)
                }, false);

JavaScript函数重载

实际上JavaScript没有这个函数重载定义

  // 四、JavaScript中的函数没有重载
                function talk(language) {
                    console.log(`语言:${language}`);
                }
 
                talk("未知");
                function talk(dream) {
                    console.log(`行为:${dream}`);
                }
                console.log(talk === talk);// 打印 true
                // 打印 行为:未知

为什么最上面的talk方法没有被调用呢?

因为在JavaScript中函数的名字是函数在堆中的指针,

两个talk都指向指定堆中的同一个函数对象,且都对它进行修改,所以必定以最后更改的为准,所以会发生覆盖现象,诸如像Java中的重载,每个重载的方法都有自己的空间,而JavaScript中只要函数名重名就会发生覆盖现象,所以JavaScript没有方法重载的概念。

但是可以实现重载的效果

// 但是我们可以借助arguments来模拟实现函数的重载。
                function overLoad() {
                    if(arguments.length === 1 && typeof arguments[0] === 'number') {
                        console.log(`数字为:${arguments[0]}`);
                    }else if(arguments.length === 1 && typeof arguments[0] === 'string') {
                        console.log(`字符串为:${arguments[0]}`);
                    }else if(arguments.length === 2) {
                        console.log(`一参是:${arguments[0]},二参是:${arguments[1]}`);
                    }
                }
                overLoad(101);// 打印 数字为:101
                overLoad("嘻哈");// 打印 字符串为:嘻哈
                overLoad(1, "小天才");// 打印 一参是:1,二参是:小天才
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值