javascript之函数

什么是函数?

 (函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。)

是封装了一段可以重复调用执行的代码,通过找个代码块,能够实现大量代码的重复使用

使用函数的方式:

  • 声明函数
  • 调用函数

声明函数的方式

JavaScript 对大小写敏感。关键词 function 必须是小写的,并且必须以与函数名称相同的大小写来调用函数。
  • 使用关键字function
// 函数名遵循变量起名的规则
function 函数名(){ // 代码块  }
  • 自变量的方式
var 函数名 = function(){ // 代码块 }

函数的调用:

在函数体后面,使用函数名加上小括号,实现函数的调用

function fn(){
    // 代码块
}
fn(); // 函数调用

调用方式:

  • 简单调用

也就是直接调用,一般适用于没有返回值的函数,就相当于直接执行函数中的代码块

function fn(){
    console.log('简单调用');
}
fn(); // 调用
  • 事件中调用

js是基于事件模型,页面加载,用户点击,移动鼠标等等,都会产生事件,事件发生其实就是调用函数

// 事件中调用普通函数
btn.onclick = function(){
    fn();
}

// 行内js调用
  • 通过链接调用

可以同构超链接调用函数

超链接
  • 禁用超链接跳转(禁止a标签href跳转)

但是,为了防止超链接自带的点击功能和添加事件点击功能相互冲突,在给超链接添加点击事件的时候。需要把超链接本身自带的点击功能取消,也就是禁止a标签进行跳转

超链接

表达式声明函数

本质是把一个函数题复制给一个变量,这个变量就是函数名

var  num = function(){
    console.log('表达式声明函数');
}
num()

参数

形参:一个省略了var关键字的变量,被称为一个特殊变量,变量的传值是一一对应的

参数有两种

  • 实参:就是实际值,比如需要使用的 1  true,函数在调用的时候传入的值就是实参
  • 形参:形式上的参数,是一个代表性的单词或者字母,函数在声明的时候,接受的值就是形参
function fn(num, sum) { // 形参 num = 3  sum = 4
    console.log(num + sum);
}
fn(3, 4); // 实参
fn(30, 4); // 实参
fn(31, 4); // 实参
fn(32, 4); // 实参
fn(33, 4); // 实参
fn(34, 4); // 实参
fn(35, 4); // 实参
fn(36, 4); // 实参

1.实参的个数少于形参的个数

实参的个数少于形参,如果形参参与运算会报错(因为没有实参传值的形参,是undefined)

function fn(num, sum, yum, tum) { // 形参 num = 3  sum = 4  tum=undefind
    console.log(num + sum + yum + tum); // NaN
}
fn(3, 4, 5); // 实参

2.实参的个数多于形参的个数

多余的实参的值会丢失

function fn(num, sum) { // 形参 num = 3  sum = 4
    console.log(num + sum );
}
fn(3, 4, 5); // 实参

如果实参特别多,形参的最适合的个数是在4-8之间

arguments

是实参的一组集合,是以数组的形式存在的

function fn() { // 形参 num = 3  sum = 4
    // console.log(num + sum );\
    console.log(arguments[0]);
}
fn('这么简单的函数', 4, 5, 4, 5); // 实参

arguments和实参以及形参的关系

定义:

  • arguments :是一个雷数组对象,包含调用函数时传入的所有参数(即实参)。
  • arguments 对象 只有以function关键字 定义函数时才有。
  • arguments 对象包含一个属性 callee - - 指向arguments对象所在的函数。
  • 声明函数时所有参数,称为形参。
  • 调用函数时传递的所有参数,称为实参

具体比较

  • arguments 是包含所有 实参 的类数组对象。
  • arguments 对象的值 会自动同步 到对应的形参,如:arguments[0] 对应第一个形参,arguments[1] 对应第二个形参
 function test(a, b, c) {
            console.log('a,b,c:', a, b, c);
            for (let item of arguments) {
                console.log(item);
            }

        }
        test(1, 2);//a,b,c: 1 2 undefined   item:1,2
        test(1, 2, 3, 4);//a,b,c: 1 2 3    item:1,2,3,4

注意的地方

  •  arguments 对象长度  , 实参决定
  • 相对应的arguments 与 形参才会建立映射关系,如:c 的变化不会影响到argument,而 a 会
  • 建立映射关系不是访问同一块内存,只是保持同步变化而已

获取函数形参的个数和实参的个数

function cheng(a,b,c){
  console.log("arguments个数:",arguments.length);
}
cheng(); // 不传参
console.log("形参的个数:",cheng.length);//分别输出:0 3

cheng(1,2);
console.log("形参的个数:",cheng.length); // 分别输出:2 3

当函数给默认值的时候,arguments 与形参的映射关系不存在

其中函数的长度,也就是形参的个数,当有默认值的时候,只计算默认值前面的形参

function cheng(a,b=1,c){
  console.log("arguments个数:",arguments.length);
}
cheng();
console.log("形参的个数:",cheng.length);  // 输出 0 1

function cheng(a,b=1,c){
  arguments[1] = 6
  console.log("b:",b); // 2
}
cheng(1,2);

封装

当代码大部分相同,把相同的保留一份,不同的变成参数

function fn(a) {
    var num = 0;
    for (var i = 0; i <= a; i++) {
        num += i
    }
    console.log(num);
}
fn(50)
fn(80)
fn(90)
fn(100)

返回值

在函数内部,计算完成的值,需要在函数外部使用,就需要使用return返回值,把这个值返回给函数本身,可以在函数外部定义一个变量,来接收这个值

function fn(){
    var a = 100;
    return a
}
var a = fn() // 100这个值 返回给函数本身,并在函数外部赋值给变量 a 
console.log(a);

什么时候使用返回值?

函数内部的值需不要在外部使用后展示,需不要返回值

返回的类型

可以返回任何类型

 return {} // number string boolean null undefined object

返回值后面的代码不会执行

function fn(){
    console.log('今天天气好好啊');
    // return   // return后面没有返回的值,返回的结果是undefined 
    return  // 有阻断代码的作用
    console.log('小芳,今天约吗?'); // 因为在return后面 是不执行的
}
console.log(fn());

获取非行间样式

/* 
el: 元素
attr: 属性
*/
var div = document.querryseletor('div')

function getStyle(el, attr) { // el = div  attr = 'height'
    if (window.getComputedStyle) { // true
        // 标准浏览器
        return window.getComputedStyle(el)[attr];
    } else {
        // 非标准浏览器
        return  el.currentStyle[attr];
    }
}
var speed = getStyle(div, 'height');

作用域

一段代码中的变量或者是函数名,并不是一直会生效,限定这个名字的可用性代码范围,就是这个名字的作用域

  • 全局作用域:在script双标签之间,就是全局作用域,在全局作用域的变量或者函数,在任何位置都可以使用
  • 局部作用域:局部作用域是以函数的花括号作为分界线,花括号内部的就是局部作用域,在局部作用域声明的函数或者变量,只能在声明的当前作用域内被访问
var a = 10; // 全局变量
function fn() {  // 全局函数
    var b = 20; // 局部变量 -- 只能在局部作用域内被访问
    console.log(a); // 局部作用域是可以访问全局作用域的变量和函数的

    return function num() { // 局部函数
        console.log(b);
    }
    // num()

    return 100
}
console.log(fn()); // fn() = 100

fn()() //调用fn()中的sum()

函数内的全局变量

不加var 直接写变量名

没有var关键字声明的变量,在任何位置都是全局的  但是不建议使用

function fn(){
    a = 10; // 没有var关键字声明的变量,在任何位置都是全局的  但是不建议使用
}
fn()
console.log(a); // 

作用域链

作用域链是给函数向上查找变量提供的一种路线,或者理解为是一种查找机制

var a = 1;
function fn() {
    var b = 2
    function num() {
        var c = 3
        function sum() {
            var d = 4
            console.log(a); // 1
            console.log(b); // 2
            console.log(c); // 3
            console.log(d); //  4
        }
        sum()
    }
    num()
}
fn()

匿名函数 - 自执行函数

语法:

//第一种
(function (){})()
//第二种
(function () {
  // 代码块
}())

//例子
(function () { 
    console.log(1); 
})()

注意:如果自执行函数上一行代码没有分号结尾 或报错

自执行函数上一行没分号报错的,解决方法:

  • 在前面加上分号  ;()
  • 在前面加上 ~()
var a = 10
// ~:解决上一行代码没有分号结尾的问题
~(function () {
    console.log(1);
})()

其他写法:

除了上面()小括弧可以把function关键字作为函数声明的含义转换成函数表达式外,

1.JavaScript的&& 与操作、||或操作、,逗号等操作符也有这个效果。

true && function () { console.log("true &&") } (); // "true &&"
false || function () { console.log("true ||") } (); // "true ||"
0, function () { console.log("0,") } (); // "0,"

// 此处要注意: &&, || 的短路效应。即: false && (表达式1)  是不会触发表达式1;
// 同理,true || (表达式2) 不会触发表达式2

2.如果不在意返回值,也不在意代码的可读性,我们甚至还可以使用一元操作符(! ~ - + ),函数同样也会立即执行。

    !function () { console.log("!"); } (); //"!"
    ~function () { console.log("~"); } (); //"~"
    -function () { console.log("-"); } (); //"-"
    +function () { console.log("+"); } (); //"+"

3.甚至还可以使用new关键字:

// 注意:采用new方式,可以不要再解释花括弧 `}` 后面加小括弧 `()` 
new function () { console.log("new"); } //"new"

// 如果需要传递参数
new function (a) { console.log(a); } ("newwwwwwww"); //"newwwwwwww"

4.赋值符号=同样也有此效用(例子中的i变量方式):

//此处 要注意区分 i 和 j 不同之处。前者是函数自执行后返回值给 i ;后者是声明一个函数,函数名为 j 。
    var i = function () { console.log("output i:"); return 10; } (); // "output i:"
    var j = function () { console.log("output j:"); return 99;}
    console.log(i); // 10
    console.log(j); // ƒ () { console.log("output j:"); return 99;}

前者是函数自执行后返回值给i ;后者是声明一个函数,函数名为j。如果是看代码,我们需要查看代码结尾是否有没有()才能区分。一般为了方便阅读,我们会采用下面这种方式:

var i2 = (function () { console.log("output i2:"); return 10; } ()); // "output i2:"
var i3 = (function () { console.log("output i3:"); return 10; }) (); // "output i3:"

自执行函数实现代码模块化

var utils = (function () {

    /* 
    @获取非行间样式
    @obj:元素
    @attr:属性
    */
    function getStyle(obj, attr) {
        if (window.getComputedStyle) {
            return window.getComputedStyle(obj)[attr]
        } else {
            return obj.currentStyle[attr]
        }
    }
    /* 
    计算和的函数
    @a:传入的范围值
    */
    function num(a) {
        var num = 0;
        for (var i = 0; i <= a; i++) {
            num += i
        }
        console.log(num);
    }
    // ............ 

    return {
        getStyle: getStyle,
        num: num,
    }

})()

// console.log(utils);  // utils = {  getStyle: getStyle, num: num,}
utils.num(100)

解决下标获取不到的问题

window.onload = function () {
    var li = document.getElementsByTagName('li')

    for (var i = 0; i < li.length; i++) {
        (function (i) { // 形参
            li[i].onclick = function () {
                console.log(i);
            }
        })(i) // 实参
    }
}

你可能感兴趣的:(javascript,开发语言,ecmascript)