JavaScript引用类型——Function


撸了今年阿里、头条和美团的面试,我有一个重要发现…>>>
Function类型
函数实际上是对象,每个函数实际上都是 Function 类型的实例。而且与其他引用类型一样具有属性和方法。函数名实际上是一个指向内存堆中某个函数对象的指针。不会与函数绑定。函数可以如下面的语法定义:

function sum (num1, num2){
    return num1 + num2;
}
    也可以像下面一样定义:

var sum = function(num1, num2){
    return num1 + num2;
}
还可以使用Function构造函数。Function构造函数可以接收任意数量的参数,最后一个参数始终被看做函数体,前面的参数被看做是新函数的参数。

var sum = new Function("num1","num2","return num1 + num2");
这种方式会导致解析两次代码(第一次是解析常规ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能。

1、函数没有重载
在ECMAScript中没有函数重载。因为函数名是作为指针的概念存在的,重复声明同一个函数名相当于覆盖指针引用,所有同一个函数名同时只能保存一个函数引用。

function fn(num1){
    return num1;
}

function fn(num1, num2){
    return num1 + num2;
}

console.log(fn(1));//NaN
    上面的代码以下面相同:

var fn = function(num1){
    return num1;
}

var fn = function(num1,num2){
    return num1 + num2;
}

console.log(fn(1));//NaN

2、函数声明与函数表达式的区别
函数声明与函数表达式的语法功能相同,但是其解析的过程却是不同的。解析器会先读取函数声明,并使其在任何执行代码前,就是说解析器会先扫描脚本,然后将声明的函数置于脚本顶部,以便于接下来执行的可以调用函数。这样就可以解释为是声明的函数可以在声明之前调用。

console.log(sum(1,2));//3
function sum(num1,num2){
    return num1 + num2;
}
    而对于函数表达式,解析器则会当作普通的赋值操作,而不会对其进行特殊的解析。下面代码会抛异常。

console.log(sum(1,2));//unexpected identifier
var sum = function(num1,num2){
    return num1 + num2;
}

3、函数内部属性
函数内部有两个特殊的对象:arguments和this。arguments是一个数组对象,包含传入函数的所有参数arguments对象有一个名叫callee的属性,指向拥有这个arguments对象的函数。对比下面的例子:

function factorial(num){
    if(num <= 1){
        return 1;
    } else {
        return num * factorial(num - 1);
    }
}
function factorial(num){
    if(num <= 1){
        return 1;
    } else {
        return num * arguments.callee(num - 1);
    }
}
第一个函数中引用了函数名,这回导致函数改名时不可用,而,第二个函数则没有这个问题。

函数内部还有一个特对象this,引用函数数据以执行的环境对象。

window.color = "red";
var o = {color:"blue"};

function sayColor(){
    console.log(this.color);
}

sayColor();//"red"

o.sayColor = sayColor;
o.sayColor();//"blue"
还有另外一个属性:caller。保存调用当前函数的引用,如果在全局作用域中调用,值为null。

function outer(){
    inner();
}

function inner(){
    console.log(arguments.callee.caller);
}

outer();

4、函数属性和方法
ECMAScript中的函数是对象,也有属性和方法。每个函数都有两个属性:length和prototype。其中,length属性表示函数要接收的命名函数的个数。

function sayName(name){
    console.log(name);
}

function sum(num1, num2){
    return num1 + num2;
}

function sayHi(){
    console.log("hi");
}

console.log(sayName.length);//1
console.log(sum.length);//2
console.log(sayHi.length);//0
每个函数包含两个非继承而来的方法:apply()和call()。apply()方法接收两个参数:一个是在其中运行函数的作用越,另一个是参数数组。第二参数可以是Array实例,也可以是arguments对象。

function sum(num1, num2){
    return num1 + num2;
}

function callSum1(num1, num2){
    return sum.apply(this,arguments);//传入arguments对象
}

function callSum2(num1, num2){
    return sum.apply(this, [num1,num2]);//传入数组
}

console.log(callSum1(10,10));//20
console.log(callSum2(10,10));//20
    对于call(),第一个参数this没有变化,但是其他参数需要直接传递函数。

function sum(num1, num2){
    return num1 + num2;
}

function callSum(num1, num2){
    return sum.call(this, num1,num2);//传入数组
}

console.log(callSum(10,10));//20
    apply()和call()能够扩充函数运行的作用域。

window.color = "red";
var o = {color : "blue"};

function sayColor(){
    console.log(this.color);
}

sayColor();//red

sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(o);//blue
    ECMAScript 5定义了一个方法:bind()。

window.color = "red";
var o = {color : "blue"};

function sayColor(){
    console.log(this.color);
}

var objectSayColor = sayColor.bind(o);
objectSayColor();//blue
支持bind()方法的浏览器有IE9+、FF4+、Safari5.1+、Opera 12+和Chrome。

这份 xmind 尤其适合: https://my.oschina.net/u/2663968/blog/3105068

1.近期想跳槽,要面试的Java程序员,查漏补缺,以便尽快弥补短板;

2.想了解“一线互联网公司”最新技术要求,对比找出自身的长处和弱点所在,评估自己在现有市场上的竞争力如何;

3.做了几年Java开发,但还没形成系统的Java知识体系,缺乏清晰的提升方向和学习路径的程序员。

发布了205 篇原创文章 · 获赞 39 · 访问量 34万+

猜你喜欢

转载自blog.csdn.net/u013321328/article/details/101149990