javascript忍者秘籍--函数是根基

本文深入解析JavaScript函数的独特之处,包括其作为第一型对象的特性、声明方式、调用机制及作用域规则,帮助读者提升JS技能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.前言

经常关注大厂面试题分享的会发现,大厂非常注重js基础,苦于啃五花八门的js框架而烦恼的你不如补一补你的js基础(求放过~这里没有贬低学js框架的意思)这编文章是整理js忍者秘籍重要的知识点和加上本人的理解,看了会让你对js的了解进一个阶层!憋怀疑,本人就是一个栗子。(微笑脸)

2.函数的独特之处

函数是第一型对象,因为函数可以像对象通过字面量进行创建,赋值变量、数组,作为函数的返回值,拥有动态创建并返回赋值的属性。函数最重要的特性是它可以被调用,而通常都是以异步的方式进行调用,其原理是浏览器事件轮询是单线程的,即每个事件都是按照在队列放放置的顺序类执行的,就是FIFO(先进先出)列表,在任何情况下单线程不可能同时执行两个程序,所以必须等待当前事件结束之后才能执行另外一个事件,就是说事件执行的时间不可知所以事件处理函数调用异步。

3.函数声明

函数是使用字面量进行声明从而创建函数值的,函数字面量由四个部分组成

1.function关键词 
2.可选名称
3.括号内部,一个以逗号分隔开的参数列表
4.函数体
复制代码

我知道你想问什么,没错!函数名是可选的,它只是函数的引用,匿名函数就是一个栗子。可以通过访问函数的name属性获取函数名

function ninja(){}
ninja.name //ninja
复制代码

另外值得注意的是书上说创建一个匿名函数并赋值给一个变量,这个变量并不是该函数的name,但是本人发现在支持ES6语法的chrome下获取函数name不是空而是匿名函数赋值给该变量的变量名。

var fn = function () {};
// ES5
fn.name // ""
// ES6
fn.name // "fn"
复制代码

也可以通过属性访问的方式获取形参长度,注意是形参不是实参,形参和实参的区别是:形参是函数声明时定义的参数,而实参是函数调用时传给函数的参数。下面会讲怎么获取实参。

var fn = function (a,b) {};
fn.length // 2
复制代码

4.函数调用

函数被调用的时候到底发生了什么?事实上函数被调用的方式对其函数内部代码执行有着巨大的影响。有四种不同的方式进行函数调用,每个方式都有细微的差别。

  • 作为一个函数调用,是简单的形式
  • 作为一个方法调用,在对象上进行调用
  • 作为构造器调用,创建一个对象
  • 通过apply()和call()方法进行调用

有趣的是在函数调用的时候都会传递两个隐式参数:arguments和this,所谓隐式就是这些参数不会显示在函数签名里,但是它们会传递给函数并在函数作用域内,在函数内可以进行访问和使用。

arguments

arguments是函数调用时传给函数的实际参数集合,可以用length属性获取集合的长度,但是arguments并不是真正的数组。

function fn (a,b,c){console.log(arguments.length) } 
fn.length // 3
fn(6,6,) // 2 
复制代码

this参数

this就是函数上下文,而this指向依赖于函数的调用方式,所以this称作调用上下文更合适。 当函数作为“函数调用“,是指区别于方法、构造器以及apply/call,this指向与widow对象

function ninja(){console.log(this)}
ninja() //window
复制代码

当函数作为“方法调用”,是指当函数被赋值给对象的一个属性,并使用引用该函数的这个属性进行调用,this指向该对象,实例如下:

var o={};
o.ninja=function(){ console.log(this)};
o.ninja(); // o
复制代码

当函数作为“构造器”进行调用时:

  • 创建一个新的对象
  • 将构造器函数作用域赋值给新对象(因此this指向了这个新对象)
  • 执行构造函数中的代码(为这个新对象添加属性)
  • 如果没有显式的返回值,返回新对象
function Ninja(){
    this.shulk=function(){console.log(this)}
}
var Ninja1=new Ninja();
var Ninja1=new Ninja();
Ninja1.shulk() //Ninja1
Ninja2.shulk() //Ninja2
复制代码

使用apply()和call()方法进行调用 在函数调用的时候JavaScript为我们提供一种可以显式指定任何一个对象作为函数的上下文,使用apply()和call()方法可以实现这种功能

function juggle(){
    var result=0;
    for( var i=0;i<arguments.length;i++){
        result=+arguments[i];
    }
    this.result=result;
}
var ninja1={},ninja2={};

juggle.apply(ninja1,[1,2,3,4]) 
console.log(ninja1.result) // 10
juggle.call(ninja2,5,6,7,8) 
console.log(ninja2.result) // 26
复制代码

在本例中可以看出apply()方法把函数juggle上下文指定给了ninja1对象,call()方法把函数juggle上下文指定给了ninja2。常见使用apply()、call()方法是在实现函数回调的时候,比如下面实现一个简单的forEach函数:

function forEach(list,callback)(){
    for(var i=0;i>list.length;i++){
        callback.call(list[i],list[i],i)
    }
}
var arr=['Tom','alice','jack'];
forEach(arr,function(e,i){
    console.log(e)
})  //Tom,alice,jack
复制代码

apply()和call()的功能基本相同,我们该选择哪个比较好呢? 如果在变量里有很多无关的值或者是指定为字面量,使用call()则可以直接将其作为参数列表传进去,但是如果这些参数已经在一个数组里了,或者很容易将其收集到数组里,apply()是更好选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值