深入探讨JavaScript函数

目录

介绍

什么是JavaScript函数?

定义函数

函数声明

函数表达式

箭头函数

函数提升

一流函数的属性

函数签名

重载

参数

默认参数

ES6之前的默认参数

默认参数ES6

函数类型

函数属性

函数方法

this对象

call()方法

apply()方法

bind()方法

总结


介绍

函数对任何编程语言都是至关重要的。将小段代码隔离和/或组织成子例程的概念具有许多用途和价值。因此,它帮助我们构造了中型到大型程序,以减少重复,并使程序和/或子程序彼此模块化。

因此,本文将深入探讨JavaScript函数。此外,如果您来自C#、Java/C / C ++等面向对象的语言,那么阅读本文肯定会对您有所帮助。原因之一是由于我的.NET背景以及有关C#编程的类思维方式。

什么是JavaScript函数?

JavaScript语言中,函数是对象。对象?是的,它是真实的。让我们看看下面的证明:

function laugh() {
    return "hahahahaha";
}

console.log(typeof(laugh)); //output: function
console.log(laugh instanceof Object); //output: true
console.log(laugh instanceof Function); //output: true

让我们看一下ECMAScript语言规范关于JavaScript函数必须说些什么。请参见下面的屏幕截图,也可以在此处访问并查看。

确认JavaScript函数是一个对象。而且,我知道您在质疑,JavaScript语言如何区分函数和对象?但是在回答之前,让我解释一下。JavaScript语言为对象定义了许多内部属性,这些内部属性由双方括号[[]]符号表示。

这些内部属性与JavaScript函数有什么关系?这些内部属性可以将函数与对象区分开,并且此属性为[[Call]]。此外,此[[Call]]属性对于函数而言是唯一的,表示可以执行该对象。因此,[[Call]]属性是函数专有的。这就是为什么在使用typeof运算符时返回“function”的原因

同样,因为函数是对象。并且,它们的行为与其他编程语言相比有所不同。因此,必须对JavaScript函数有一个很好的了解。

定义函数

函数声明

一个函数声明开头的function关键字,加上函数的名称。最后,函数的内容(也称为代码块)用花括号括起来。让我们在下面看一个例子。

function smile(happythought1, happythought2) {
    
    return "My happy thoughts are " + happythought1 + " and " + happythought2;
}

函数表达式

一个函数表达式不需要function关键字后的名称。此外,这些函数被视为匿名函数,因为该函数本身没有名称。并且,它由变量或属性名称引用。

让我们看下面的例子:

const smileAgain = function (happythought1, happythought2) {
    return "My happy thoughts are " + happythought1 + " and " + happythought2;
};

上面的示例代码实际上为该smileAgain变量分配了一个函数值。如您所见,函数表达式与函数声明非常相似,唯一的例外是缺少名称和分号。在提升部分,它们的差异更大。

箭头函数

最近,JavaScriptES6版本引入了箭头函数。并且,其特征为=>对我来说就像箭一样!)。此外,它使我们能够使用较短的语法。因此,它的行为类似于函数表达式,但是由于箭头运算符和lambda表达式的组合而看起来有所不同。

以下是有关箭头函数需要记住的内容:

  • 它由零个或多个参数组成,这些参数围绕在圆括号内,也称为圆括号()
  • =>操作符紧随其后
  • 在箭头运算符之后,其后是一个函数主体。请记住,如果存在多个表达式,则仅需用大括号{}括住主体。因此,如果只有一个表达式,则可以省略花括号。

请参见下面的代码段:

//declarative function
var showFavoriteLanguage(language) {
    return `I love ${language}`;
}

//arrow function equivalent
const showFavoriteLanguage= (language) => `I love ${language}`;

在本节中,让我们将函数声明转换为箭头函数。首先,让我们定义一个函数。

function getProductOfTwoNumbers(num1, num2) {
    return num1 * num2;
}

其次,将其转换为箭头函数。

const getProductOfTwoNumbers = (num1, num2) => {
    return num1 * num2;
}

看起来像一个函数表达式。对?想要一些样式吗?我们可以删除花括号。

const getProuductOfTwoNumbers = (num1, num2) => num1 * num2;

很好!对我来说看上去很好。

如果您很好奇,如果我们只有一个参数该怎么办?让我们在下面看一个例子。

//gets the first element in the passed array
const getFirstElement = (arr) => arr[0];

//squares the passed number
const squareNum = (num) => Math.pow(num, 2);

函数提升

在上一节中,我们了解了如何定义function。此外,我们已经看到函数声明函数表达式有多么相似,但是在某些方面有所不同。

函数声明被提升到顶部。因此,您可以在代码中使用函数后定义函数,而不会引起错误。

让我们看下面的例子:

console.log(chuckle()); //output: Hehehehe

function chuckle() {
    return "Hehehehe";
}

请记住,函数提升仅发生在函数声明中。原因之一是预先确定了函数名称。而函数表达式(包括箭头函数)不能提升,因为它仅通过变量来引用。

一流函数的属性

这就是使JavaScript函数强大的原因。因为JavaScript语言具有一流的函数。而且,根据MDNMozilla开发人员网络):

当一种编程语言的函数像任何其他变量一样被对待时,它被称为具有一流的函数。例如,用这种语言,一个函数可以作为参数传递给其他函数,可以由另一个函数返回,也可以作为值分配给变量。

并且,您可以在这里查找。

这里有些例子:

  • 将函数分配给变量:
//assign a variable to a function

const love = function () {
    return "I love JavaScript";
}

 //output: I love JavaScript
console.log(love());

//end of assign a variable to a function
  • 向对象添加函数:
//add function to objects 

const sayHello = function (name) { 

    return "Hi! My name is " + name;
}

const customer = {
    name: "Jin Vincent N. Necesario",
    sayHello:  sayHello
};

let name = customer.name;

//output: Hi! My name is Jin Vincent N. Necesario
console.log(customer.sayHello(name));

//end of function to objects
  • 将函数作为参数传递给其他函数:
//pass function as an argument 

function sayFavorite() {
    return "Hi! My Favorite programming language is ";
}

function favoriteLanguage(func1, language) {
    
    return func1() + language;
}

//output: Hi! My Favorite programminglanguage is JavaScript
console.log(favoriteLanguage(sayFavorite, "JavaScript"));

//end of pass function as an argument
  • 从另一个函数返回函数:
//return a function 

function followYou() {
    return function () { 
        return "Your part of me I can't let go!!!";
    };
}          

const follow = followYou(); 

//output: Your part of me I can't let go!!!
console.log(follow());

//end of return a function

函数签名

重载

如果您来自诸如C#,Java/C / C ++的静态语言,则这些语言支持函数重载。并且,单函数具有多个签名的能力。此外,函数签名由函数名称,参数数量和该函数接受的参数类型组成。但是,JavaScript语言函数没有签名。因此,JavaScript缺少函数重载。

让我们尝试看看当我们声明两个具有相同名称的函数时会发生什么。

function giveLove(act){
    console.log(act);
}

function giveLove() {
    console.log("Trust your partner");
}

//output: Trust your partner
giveLove("Love and trust your partner");  

根据我们的示例,如果您使用的是面向对象的语言,则可以期望输出为"Love and trust your partner"。而且,由于JavaScript缺少重载,因此它执行了没有参数的函数。因此,输出为"Trust your partner"

参数

要理解的另一个概念是JavaScript函数可以传递任何数量的参数而不会引起错误。这是因为函数参数存储为称为arguments类似数组的对象

如果您想了解有关数组对象的更多信息,请访问此处

而且,参数可以增长为包含许多值。length属性确定该函数中存在多少个值。最后,arguments对象可在任何函数中自动使用。因此,函数中存在的命名参数本质上是为了方便起见,并且不限制函数可以接受的参数数量。

让我们看下面的例子:

function decidedToLove() {

    let len = arguments.length,
        messageResult = "",
        counter = 0;

    while (counter < len) {
        messageResult += counter === 0 ? arguments[counter]: `,${arguments[counter]}`;
        counter++;
    }

    return messageResult;
}

//output: I'm in love
console.log(decidedToLove("I'm in love"));

//output: Don't be mean,Leave my heart alone
console.log(decidedToLove("Don't be mean", "Leave my heart alone"));

//output: love,trust,appreciate
console.log(decidedToLove("love", "trust", "appreciate"));

默认参数

ES6之前的默认参数

ES6之前,没有明确的方法为函数参数分配默认值。因此,开发人员可以在为参数分配默认值之前检查这些参数。

让我们看下面的例子:

function yourAmazing(arg1, arg2, arg3) {
    
    arg1 = arg1 || "arg1";
    arg2 = arg2 || "arg2";
    arg3 = arg3 || "arg3";

    return `${arg1}, ${arg2}, ${arg3}`;
}

//using all the default values
//output: arg1, arg2, arg3
console.log(yourAmazing()); 

//using the last two default values
//output: my-first-argument, arg2, arg3
console.log(yourAmazing("my-first-argument"));

//using the last default value
//output: my-first-argument, my-second-argument, arg3
console.log(yourAmazing("my-first-argument", "my-second-argument"));

//sending all with values 
//output: my-first-argument, my-second-argument, my-third-argument
console.log(yourAmazing("my-first-argument", "my-second-argument", "my-third-argument"));

让我们看另一个示例,这次检查传递的参数是否未定义。

function areYouAnAngel(arg1, arg2, arg3) {
    
    arg1 = arg1 === undefined ? 1 : arg1;
    arg2 = arg2 === undefined ? 2 : arg2;
    arg3 = arg3 === undefined ? 3 : arg3;

    return `${arg1}, ${arg2}, ${arg3}`;
}

//using all the default values
//output: 1, 2, 3
console.log(areYouAnAngel());

//using the last two default values
//output: my-first-argument, 2, 3
console.log(areYouAnAngel("my-first-argument"));

//using the last default value
//output: my-first-argument, my-second-argument, 3
console.log(areYouAnAngel("my-first-argument", "my-second-argument"));

//sending all with values 
//output: my-first-argument, my-second-argument, my-third-argument
console.log(areYouAnAngel("my-first-argument", "my-second-argument", "my-third-argument"));

默认参数ES6

最近,JavaScript语言具有一种新的语法,该语法可以更轻松,更优雅地执行默认参数。万岁!

  • 默认参数示例:
function myGifts(gift1 = "health", gift2 = "wealth", gift3 = "love") {
    return `${gift1}, ${gift2}, ${gift3}`;
}

//using all the default values
//output: health, wealth, love
console.log(myGifts());

//using the last two default values
//output: healthy body, wealth, love
console.log(myGifts("healthy body"));

//using the last default value
//output: healthy body, cash-flow, love
console.log(myGifts("healthy body", "cash-flow"));

//sending all with values 
//output: healthy body, cash-flow, family
console.log(myGifts("healthy body", "cash-flow", "family"));
  • 将未定义的值传递给默认参数:
function youAreGreat(talent1 = 'write', talent2 = 'speak', talent3 = 'code') {
    
    return `${talent1}, ${talent2}, ${talent3}`;
}

//using all the default values
//output: write, speak, code
console.log(youAreGreat());

//output: read and write, speak, code
console.log(youAreGreat("read and write", undefined, undefined));

//output: write, teach and speak, code
console.log(youAreGreat(undefined, "teach and speak", undefined));

//output: write, speak, write books
console.log(youAreGreat(undefined, undefined, "write books"));
  • 在默认参数内使用表达式:
function myCashGifts(gift1 = 1000, gift2 = 2000, 
         gift3 = (Math.random() * (5000 - 1000) + 1000)) {

    return `Your total cash: $${gift1 + gift2 + gift3}`;
}

//note: the value is random the output should be different
//output: Your total cash: $4307.070424503042
console.log(myCashGifts());

函数类型

同样,JavaScript函数是对象。因此,函数具有与其他对象一样的属性和方法。让我们看看如何使用这些属性和方法。

函数属性

  • length属性确定函数中的总参数。
  • prototype属性引用实际的函数对象。

让我们看一个函数属性的例子:

function setGift(gift1, gift2) {
    
    return `My gifts this coming Christmas are ${gift1} and ${gift2}`;
}

//output: 2
console.log(setGift.length);

//output: object {}
console.log(setGift.prototype);

函数方法

this对象

JavaScript中的所有作用域都有一个this对象,代表该函数的调用对象。例如,在全局范围内,this表示全局对象(window)。此外,一旦函数在附加到对象时被调用,默认情况下的this值等于该对象。因此,您可以引用this而不是直接引用方法内部的对象。

让我们看下面的例子:

function showFullName() {
    console.log(this);
    console.log(this.name);
}

const name = "Jin Vincent Necesario";

const person = {
    name: "Jin Necesario",
    showFullName: showFullName
}

const pet = {
    name: "Bruno",
    showFullName: showFullName
}

//this value is equivalent to window object
//output: Jin Vincent Necesario 
showFullName(); 

//this value is equivalent to person object
//output: Jin Necesario
person.showFullName();

//this value is equivalent to pet object
//output: Bruno
pet.showFullName();

了解this函数的价值是使用JavaScript进行良好的面向对象编程的关键。有三种方法,使您能够改变this的值,这些就是callapplybind方法。

当您要操纵this的值时,apply()call()方法几乎相同。唯一的区别是,apply()需要类似数组的对象,而call()需要传递充当this和所需参数的对象。让我们通过示例逐一查看它们。

call()方法

function showFullName(caller) {
    return `Caller: ${caller} having a value of ${this.name}`;
}

window.name = "Jin Vincent Necesario";

const person = {
    name: "Jin Necesario"
}

const pet = {
    name: "Bruno"
}

//output: Caller: global, the window object having a value of Jin Vincent Necesario
console.log(showFullName.call(this.window, "global, the window object"));

//output: Caller: person variable having a value of Jin Necesario
console.log(showFullName.call(person, "person variable"));

//output: Caller: pet variable having a value of Bruno
console.log(showFullName.call(pet, "pet variable"));

apply()方法

function showFullName(caller, param1) {

    return `${param1}. The caller: ${caller} having a value of ${this.name}.`;
}

window.name = "Jin Vincent Necesario";

const person = {
    name: "Jin Necesario"
}

const pet = {
    name: "Bruno"
}

//output: Hi!. The caller: global, the window object having a value of Jin Vincent Necesario.
console.log(showFullName.apply(this.window, ["global, the window object", "Hi!"]));

//output: Hello!. The caller: person variable having a value of Jin Necesario.
console.log(showFullName.apply(person, ["person variable", "Hello!"]));

//output: Good day!. The caller: pet variable having a value of Bruno.
console.log(showFullName.apply(pet, ["pet variable", "Good day!"]));

bind()方法

如果您想要一个新的函数实例,其this值绑定到您提供的对象。让我们看下面的例子:

const bike = {
    speed: 10,
    start: function () {
        return `${this.speed} Km/h`;
    }
};

const motorcycle = {
    speed: 40, 
    start: function () {
        return `${this.speed} Km/h`;
    }
}

let upgradeBike = bike.start.bind(motorcycle);

//output: 40 Km/h
console.log(upgradeBike());

总结

在本文中,我们讨论了有关JavaScript函数的许多概念。我们首先回答:什么是JavaScript函数,如何定义函数,为什么JavaScript是一流函数。最后,我们研究了函数签名和函数类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值