ES5函数

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/CJXBShowZhouyujuan/article/details/86033571

函数声明

function 声明

function name (s) {}
name(s)

函数表达式

var name = function (s) {};
name(s)

构造函数

function myFun (arg1,arg2) {
    this.a = arg1
    this.b = arg2
}
var f = new myFun('aa', 'bb')
f()

函数的重复声明

如果一个函数被多次声明,后面的声明会覆盖前面的声明

函数名的提升

函数名视同变量,function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。

f();
function f() {}

函数表达式的方式会报错

f();
var f = function () {};
// 上面的代码类似于
var f;
f(); // 此时f只是被声明了,没被赋值 等于undefined
f = function () {};

如果同时采用function命令和赋值语句声明同一个函数,最后总是采用赋值语句的定义。

var f = function () {
    console.log(1)
}
function f () {
    console.log(2)
}
f() // 1

函数的属性和方法

name 返回函数的名字

function f1 () {}
f1.name // "f1"
var f2 = function () {};
f2.name // "f2"
var f3 = function myName () {}
f3.name // 'myName'

length 属性

length 返回的是函数定义之中的参数的个数。

函数本身的作用域

函数的作用域,就是其声明时所在的作用域,与其运行时所在的作用域无关

var a = 1
var x = function () {
    console.log(a)
} // x函数声明所在的作用域
function f () {
    var a = 2; // 函数内变量
    x() 
    // x函数运行所在的作用域
    // 函数x不会调用函数f作用域中的变量a
}
f() // 1
// 这个反之亦然
function foo () {
    var x = 1;
    function bar () {
        console.log(x)
    } 
    // bar 在函数内部,变量引用的也是函数内的
    return bar;
}
var x = 2;
var f = foo();
f() // 1

参数

函数参数不是必须的,允许省略参数

function f (a,b) {
    return a;
}
f (1,2,3) // 1
f(1) // 1
f() // undefined

传递方式

函数参数:数值、字符串、布尔值,

传值方式是值传递,在函数体内修改参数值,不会影响到函数外部

var p = 2;
function f(p) {
    p = 3;
}
f(p)
console.log(p) // 2

函数的参数:数组、对象、其他函数

传值方式:地址传递,传入函数的是原始值的地址,内部修改会影响原始值

var obj = { p: 1}
function f(o) {
    o.p = 2;
}
f(obj)
console.log(obj.p) // 2

如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值

var obj = [1,3,4]
function f(o) {
    o = [2,3,4]
}
f(obj)
console.log(obj) // [1,3,4]
// 形参 o 的值实际参数是obj的地址,重新对o复制,导致了o指向另一个地址。所以原来的不受影响
// 传递函数
function test (obj) {
    let x = obj.a
    let y = obj.b
    function xx (x,y) {
        obj.success(x+y)
    }
    xx(x,y)
}
test({
    a:1,
    b:2,
    success:function(res) {
        console.log(res) // 3
    }
})

arguments 对象

javaScript 允许函数有不定数量的参数,所以需要一种机制,在函数体内去读取所有的参数 => arguments

正常模式下 arguments 对象可以在运行时修改参数

var f = function(a, b) {
    arguments[0] = 2;
    arguments[1] = 3;
    console.log(a,b) // 2,3
}
f(1,1)

在严格模式下,arguments 对象是一个只读的对象,修改无效

var f = function(a,b) {
    'use strict' // 开始严格模式
    arguments[0] = 3 // 无效
}
f (1,1)
// arguments.length 传递了几个参数

arguments 很像数组,但它是一个对象,一些数组的方法不能在它上面使用。除非转换为数组

// 把对象转换为数组
var args = Array.prototype.slice.call(arguments)

重点关注 call() 、apply() 的应用和讲解

函数的其他知识点

闭包

场景描述:在函数体外部想要获取函数体内的参数

闭包可以简单的理解为:定义在一个函数内部的函数。闭包最大的特定就是:它可以记住“诞生”的环境。(实质上是函数声明决定函数的运行环境)

闭包就是将函数内部和外部连接起来的一座桥梁

function f1 () {
    var n = 999
    function f2 () {
        console.log(n)
    }
}
f1() // 999  闭包就是函数f2

闭包的特点:(1)可以读取函数内部的变量

(2) 让这些变量始终保持在内存中。

function createIncementor (start) {
    return function () {
        return start++;
    }
}
var inc = createIncementor(5)
inc() // 6
inc() // 7
// 通过闭包,start的状态被保留了,每一次调用都是在上一次调用的基础上进行计算
//inc始终在内存中,而inc的存在依赖于createIncrementor,因此也始终在内存中,不会在调用结束后,被垃圾回收机制回收。

闭包的另一个用处,是封装对象的私有属性和私有方法

function Persion (name) {
    var _age;
    function setAge (n) {
        _age = n;
    }
    function getAge () {
        return _age;
    }
    return {
        name: name,
        getAge: getAge,
        setAge: setAge
    }
}
var p1 = Persion('张三')
p1.setAge(25)
p1.getAge() // 25
// 函数Person的内部变量_age,通过闭包getAge和setAge,变成了返回对象p1的私有变量

外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题

立即调用函数

JavaScript 引擎规定,如果function关键字出现在行首,一律解释成语句。不应该以圆括号结尾。

解决方法就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面

// 立即执行函数
(function () {}());
(function () {})();

上面两种写法最后的分号都是必须的。如果省略分号,遇到连着两个 IIFE,可能就会报错

猜你喜欢

转载自blog.csdn.net/CJXBShowZhouyujuan/article/details/86033571
ES5