常用的javascript函数-JavaScript 函数定义

function sum1(n1,n2){
    return n1+n2;
};

该函数不会在声明后立即执行,而是在我们需要时调用

分号用于分隔可执行的 JavaScript 语句。 由于函数声明不是可执行语句,因此它不以分号结尾。

函数表达式,也称为函数字面量

JavaScript 函数可以通过表达式来定义

函数表达式可以存储在变量中:

var sum2=function(n1,n2){
    return n1+n2;
};

将函数表达式存储到变量中后,变量还可以用作函数:

两者之间的区别:解析器将首先读取函数声明并使其可访问常用的javascript函数,然后再执行任何代码; 而函数表达式必须等到解析器执行到它所在的代码行才可以真正被解释和执行。

var x = function (a, b) {return a * b};
var z = x(4, 3);

上面的函数实际上是一个匿名函数(函数没有名字)。 函数存储在变量中,不需要函数名,通常通过变量名来调用。 上面的函数以分号结尾,因为它是一条执行语句。

函数的几种写法

1 常用写法:

function Test(){
    alert("test");
}
Test()

2 匿名函数:

var test=function(){
    alert("test");
}
test();

3个自调用函数:

(function () {   
    alert('test'); 
})();

4.函数嵌套:

var Test = {
    test1:function(){
        alert('test1');
    },
    test2:function(){
        alert('test2');
    }
}
var t = Test.test1();

5 函数继承和构造函数

var Test = function(){};
Test.prototype={
    test1:function(){
        alert('test1');
    },test2:function(){
        alert('test2');
    }
}
var t = new Test();
t.test2();

Function() 构造函数

在上面的例子中,我们了解到函数是通过关键字function来定义的。函数也可以通过外部JavaScript函数构造函数(Function())来定义

var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);

事实上,为什么要使用构造函数。 上面的例子可以写成:

var myFunction = function (a, b) {return a * b}
var x = myFunction(4, 3);

在JavaScript中,很多时候,你需要避免使用new关键字

功能提升(吊装)

提升是 JavaScript 的默认行为常用的javascript函数,即将当前范围提升到后一个范围。

提升适用于变量声明和函数声明,因此可以在声明之前调用函数:

 myFunction(5);
 function myFunction(y) {
     return y * y;
 } 

使用表达式定义函数时未能引发

 myFunction(5);
 var myFunction = function(y) {
     return y * y;
 } 

上面的代码运行时会报错,因为该函数位于初始化语句中,而不是函数声明中。 也就是说,变量myFunction不会持有该函数的引用,直到该函数所在的句子; 而且,由于第一行代码会导致“意外标识符”(unexpectedidentifier)错误,因此实际上不会执行到下一行。

除了声明时可以通过变量访问函数的区别外,函数声明和函数表达式的语法是等效的。

自调用函数

函数表达式可以是“自调用”。 自调用表达式是手动调用的。 如果表达式紧接在 () 前面,则会手动调用。 声明的函数不能自调用。 通过添加括号表明它是一个函数表达式:

(function () {
    var x = "Hello!!";      // 我将调用自己
})();

上面的函数实际上是一个匿名自调用函数

自调用函数可用于传递参数和返回值

var sum=(function(x,y){
  return x+y;
})(2,3);
console.log(sum);

严格来说,自执行函数也称为函数表达式。 它主要用于创建新的作用域。 在此作用域中声明的变量不会与其他作用域中的变量发生冲突或混淆。 它们大多数以匿名函数的形式存在。 ,并立即手动执行。

JavaScript 函数可作为值使用

function myFunction(a, b) {
    return a * b;
}
var x = myFunction(4, 3);

JavaScript 函数可以作为表达式使用:

function myFunction(a, b) {
    return a * b;
}
var x = myFunction(4, 3) * 2;

函数是对象

在 JavaScript 中使用 typeof 运算符来确定函数的类型将返回“function”,但 JavaScript 函数越来越精确地被描述为对象。

JavaScript 函数有属性和技巧。

argument.length 属性返回函数调用接收到的参数数量:

function myFunction(a, b) {
    return arguments.length;
}
document.getElementById("demo").innerHTML = myFunction(4,3,6,5);

toString() 方法以字符串形式返回函数:

函数被定义为对象的属性,这称为对象模式。

如果函数用于创建新对象,则称为该对象的构造函数

JavaScript 函数参数

JavaScript 函数不对参数(arguments)的值执行任何检查

函数显式参数和隐藏参数(实参)

函数显式参数在函数定义时被枚举

functionName(parameter1, parameter2, parameter3) {
    code to be executed
}

函数隐藏参数(argument)在函数调用时传递给函数的真实值

参数规则

JavaScript函数定义时,参数不指定数据类型,不检查隐藏参数(实参),不测量隐藏参数(实参)数量

默认参数

如果函数调用时缺少参数,参数将被设置为:默认未定义

有时这是可以接受的,但建议为参数设置默认值:

function myFunction(x, y) {
    if (y === undefined) {
          y = 0;
    } 
}

或者,以更简单的形式:

function myFunction(x, y) {
    y = y || 0;
}

y || 如果 y 已经定义,则返回 y,因为 y 为 true,否则返回 0,因为 undefined 为 false

如果函数调用时设置的参数太多,参数会很难引用,因为很难找到对应的参数名。只能用arguments对象来调用

参数对象

JavaScript 函数有一个外部对象参数对象。 参数对象包含函数调用的参数的链接列表。 您可以通过以下方法轻松找到各个参数的值:

x = findMax(1, 123, 500, 115, 44, 88);
function findMax() {
    var i, max = 0;
    for (i = 0; i  max) {
            max = arguments[i];
        }
    }
    return max;
}

或者创建一个函数来计算所有值的总和:

x = sumAll(1, 123, 500, 115, 44, 88);
function sumAll() {
    var i, sum = 0;
    for (i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
}

按值传递参数

函数调用的参数是函数的参数。

如果函数改变了参数的值,参数的初始值(在函数外部定义的)将不会改变。

var x = 1;
function myFunction(x) {// 通过值传递参数
    x++; //修改参数x的值,将不会修改在函数外定义的变量 x
    console.log(x);
}
myFunction(x); // 2
console.log(x); // 1

通过对象传递参数

对象的值可以在 JavaScript 中引用,因此在函数内更改对象的属性将更改其初始值。

修改对象属性可以在函数外部应用(全局变量)。

var obj = {x:1};
function myFunction(obj) {// 通过对象传递参数
    obj.x++; //修改参数对象obj.x的值,函数外定义的obj也将会被修改
    console.log(obj.x);
}
myFunction(obj); // 2
console.log(obj.x); // 2

JavaScript 函数调用

JavaScript函数的调用方法有4种,每种方法的区别在于this的初始化

这个关键字

一般来说,在Javascript中,函数执行时this指向当前对象

请注意,这是一个保留关键字,您无法更改它的值

调用 JavaScript 函数

函数中的代码在函数被调用后执行

作为函数调用

function myFunction(a, b) {
    return a * b;
}

myFunction(10, 2); // myFunction(10, 2) 返回 20

上面的函数不属于任何对象。 但它仍然是 JavaScript 中默认的全局对象。

HTML 中默认的全局对象是 HTML 页面本身,因此函数属于 HTML 页面。

浏览器中的页面对象就是浏览器窗口(窗口对象)。上面的函数将手动改为窗口对象的函数

myFunction() 与 window.myFunction() 相同:

function myFunction(a, b) {
    return a * b;
}
window.myFunction(10, 2);    // window.myFunction(10, 2) 返回 20

这是调用 JavaScript 函数的常见方法,但不是良好的编程实践。 全局变量、方法或函数容易出现命名冲突 bug

全局对象

当函数没有被自己的对象调用时,this的值会被做成全局对象。

Web 浏览器中的全局对象是浏览器窗口(窗口对象)。

该实例返回的值是窗口对象:

function myFunction() {
    return this;
}
myFunction();                // 返回 window 对象

将函数作为全局对象调用,使得this的值成为全局对象。使用window对象作为变量很容易导致程序崩溃

函数调用为

在 JavaScript 中,您可以将函数定义为对象技巧。

以下示例创建一个具有两个属性(firstName 和 lastName)和一个方法 (fullName) 的对象 (myObject):

var myObject = {
    firstName:"John",
    lastName: "Doe",
    fullName: function () {
        return this.firstName + " " + this.lastName;
    }
}
myObject.fullName();         // 返回 "John Doe"

fullName 方法是一个函数。 函数属于对象。 myObject 是该函数的所有者。

this 对象,保存 JavaScript 代码。 实例中 this 的值是 myObject 对象。

测试以下! 修改 fullName 方法并返回该值:

var myObject = {
    firstName:"John",
    lastName: "Doe",
    fullName: function () {
        return this;
    }
}
myObject.fullName();          // 返回 [object Object] (所有者对象)

将函数作为对象调用将会导致 this 的值变成对象 myObject 本身

使用构造函数调用函数,参数前面必须加破折号

如果在函数调用之前使用new关键字,则调用构造函数。 这看起来像是创建了一个新函数,但 JavaScript 函数实际上是重新创建的对象:

// 构造函数:
function myFunction(arg1, arg2) {
    this.firstName = arg1;
    this.lastName  = arg2;
}
// This creates a new object
var x = new myFunction("John","Doe");
x.firstName;                             // 返回 "John"

构造函数调用创建一个新对象。新对象继承构造函数的属性和技巧

构造函数中的 this 关键字没有值。 this 的值是在调用函数时实例化对象(新对象)时创建的。

将函数作为函数调用

在 JavaScript 中,函数就是对象。 JavaScript 函数有其属性和技巧。 call() 和 apply() 是预定义的函数方法。 可以使用两种技巧来调用函数,这两种方法的第一个参数都必须是对象本身。

//call()
function myFunction(a, b) {
    return a * b;
}
myFunction.call(myObject, 10, 2);      // 返回 20
 
//apply()
function myFunction(a, b) {
    return a * b;
}
myArray = [10,2];
myFunction.apply(myObject, myArray);   // 返回 20

两种方法都使用对象本身作为第一个参数。 两者的区别在于第二个参数:apply传入的是参数链表,即多个参数组合成一个链表传入,而call则是作为call的参数传入(从第二个参数开始) )。 call和apply的第一个参数是this指针要指向的对象

在 JavaScript 严格模式下,调用函数时第一个参数将成为 this 的值,即使该参数不是对象。

在 JavaScript 非严格模式下,如果第一个参数的值为 null 或未定义,则会使用全局对象。

使用 call() 或 apply() 方法,您可以设置 this 的值并将其作为现有对象的新方法调用

JavaScript 闭包

JavaScript 变量可以是局部变量或全局变量

私有变量可以使用闭包

局部变量和全局变量

函数可以访问函数内部定义的变量

function myFunction() {
    var a = 4;
    return a * a;
}

函数还可以访问函数外部定义的变量

var a = 4;
function myFunction() {
    return a * a;
}

在后一种情况下,a 是一个全局变量。 网页中的全局变量属于window对象。 全局变量适用于页面上的所有脚本。

在第一个实例中,a 是局部变量。 局部变量只能在定义它的函数内部使用。 不适用于其他函数或脚本代码。 尽管全局变量和局部变量具有相同的名称,但它们也是两个不同的变量。 修改其中一个不会影响另一个的值。

变量声明是如果不使用 var 关键字,那么它就是全局变量,即使它是在函数内定义的

可变的生命周期

全局变量的作用域是全局的,即在整个JavaScript程序中,全局变量无处不在。 函数内部声明的变量只能在函数内部起作用。 这些变量是局部变量,作用域是局部的; 函数的参数也是局部的,并且仅在函数内部起作用。

反困境

想象一下,如果您想对某些值进行计数,并且计数器在所有函数中都可用。 您可以使用全局变量、函数将计数器设置为递增:

var counter = 0;
function add() {
    counter += 1;
}
add();
add();
add();
// 计数器现在为 3

执行 add() 函数时,计数器值会发生变化。 但问题来了,页面上的任何脚本都可以更改计数器,即使不调用 add() 函数。 如果我在函数内声明计数器,则在不调用该函数的情况下很难更改计数器的值:

function add() {
    var counter = 0;
    counter += 1;
}
add();
add();
add();
// 本意是想输出 3, 但事与愿违,输出的都是 1 !

上面的代码很难正确输出,每次调用add()函数时,计数器都会被设置为1。JavaScript内置函数可以解决这个问题

JavaScript 内置函数

所有函数都可以访问全局变量。 事实上,在 JavaScript 中,所有函数都可以访问其父作用域。 JavaScript 支持嵌套函数。 嵌套函数可以访问上一层的函数变量。

在此示例中,嵌套函数 plus() 可以访问父函数的计数器变量:

function add() {
    var counter = 0;
    function plus() {counter += 1;}
    plus();    
    return counter; 
}

如果我们可以从外部访问 plus() 函数,这将解决计数器的困境。 我们还需要确保 counter = 0 只执行一次。 我们需要关闭。

JavaScript 闭包

var add = (function () {
    var counter = 0;
    return function () {return counter += 1;}
})();
add();
add();
add();
// 计数器为 3

变量add指定函数调用本身的返回字值。 自调用函数仅执行一次。 将计数器设置为 0。并返回一个函数表达式。 add 变量可以用作函数。 最酷的部分是它可以访问函数上方范围内的计数器。 这称为 JavaScript 闭包。 它使函数可以拥有私有变量。 计数器受匿名函数作用域保护,只能通过 add 方法更改。