javascript笔记整理系列 - 函数

1 函数定义

  1. 在JavaScript中,函数也是对象,是Function的实例。
  2. 我们可以将函数当作对象使用,包括当作函数的参数等。typeof getSum; //"function"
  3. 函数有属性和方法。
  4. 函数内部的变量arguments是参数数组。
  5. 函数难点在于闭包、原型链等。

1.1 函数声明

function funName(parameters){
    //...
}

1.2 函数表达式

1 函数表达式实际上是创建一个匿名函数,然后存储在变量中。

var getSum = function(a, b){
    return a + b;
}

2 函数表达式可以包含名称,在递归时很有用

var f = function fact(x){ 
    return x * fact(x-1);
}

1.3 Function构造函数

var sum = new Function("num1", "num2", ..., "return num1 + num2");

2 函数返回值

  1. 函数体中遇到return则停止执行。
  2. 若return后有值或表达式,则返回。
  3. 若return后无值或表达式,或函数中没有return,则返回undefined。

3 函数提升

  1. 函数声明会被移动到其作用域的顶端。
  2. 函数声明的调用可以在函数声明之前。
  3. 函数表达式无法提升。

4 函数内部对象

4.1 arguments

  1. arguments是一个包含函数实参列表的对象,长度可超过形参个数和。
  2. arguments的callee属性指向拥有该arguments对象的函数,便于递归调用。
  3. 严格模式下禁用callee属性。

4.2 this

  1. 默认情况下,this指向调用函数的对象。
  2. 若想改变默认情况this指向,则需使用call()或apple()方法。
  3. 在全局作用域下创建函数,非严格模式,函数调用上下文是全局对象,严格模式则是undefined,可用于确定是否严格模式。
var strict = (function(){return !this})();

this指针问题
1. 当函数作为方法调用,则this指向调用它的对象。
2. 当函数独立调用,this指向window(非严格模式)/undefined(严格模式)
3. 当this在对象属性的表达式中调用,若对象在全局声明,this指向全局对象。
4. 当this在对象属性的表达式中调用,若对象非全局声明,this指向window(非严格模式)/undefined(严格模式)

4.3 caller

函数对象属性caller指向调用当前函数的函数。

var outer = function(){
    inner();
}
var inner = function(){
    console.log(inner.caller);    //function(){inner();}
}
  1. 控制台会输出caller指向的函数对象的源代码。
  2. 当在全局作用域中调用当前函数,caller属性值为null。
  3. 严格模式下就能用caller属性

5 作为命名空间的函数

  1. 因为函数包含作用域,所以将临时变量放在函数中,防止全局污染。
  2. 这些临时变量只会使用一次,所以将这些变量放在自执行函数中,内部返回目标对象。如果需要就用变量指向返回对象,如果不需要则自动垃圾回收。
  3. 自调用函数其实就是将匿名函数当作一个函数对象,然后调用。
(function(){
    return 3 + 5;
})();

如果上面的代码看起来有点迷糊,那么拆分来看:

//首先我们将匿名函数赋值给变量,形成一个函数表达式:
var getSum = function(){
    return 3 + 5;
}
//然后我们调用getSum方法:
getSum();

//还看不明白?没关系 我们把上面一行代码的setSum再换回匿名函数
(匿名函数)();
//到这里是否明白了呢?

6 函数的方法

6.1 toString()

函数的toString方法返回值为函数声明的代码字符串。

var fun = function(){
    return 3 + 5;
}
console.log(fun.toString());    //function(){//...};

6.2 call()

  1. call方法用来替换方法内部的this指向。正常调用函数,函数内部this指向调用函数的对象;使用call方法可以指定函数内部this指向的对象。
  2. 传入的第一个参数即函数内部this指向的对象。
  3. 如果不传参数,默认指向全局对象。

funObj.call(thisObj, arg1, arg2,...)

6.3 apply()

  1. apply方法与call方法其实相同,不过只有两个参数,第二个参数是方法实际参数的数组集合。
    funObj.apply(thisObj, arrayArgs);

6.4 巧用apply方法

当某方法需要传多个参数,但多个参数是存在数组中时,可以用此方法传参:

var fun = function(a,b,c,d){
    return a + b + c + d;
}
var args = [1,2,3,4];
console.log(fun.apply(this,args));

6.5 bind()

语法:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

6.5.1 用法

例子:

//a.js
var foo = {
    bar: 1,
    eventBind: function () {
        var _this = this;
        $('.someClass').on('click', function (event) {
            /* Act on the event */
            console.log(_this.bar); //1
        });
    }
}

上面例子中的eventBind中的click事件内无法直接访问foo对象内部的this,所以我们将this赋值给中间层_this,再从事件中调用_this。
简化一下:

//b.js
var foo = {
    bar: 1,
    eventBind: function () {
        $('.someClass').on('click', function (event) {
            /* Act on the event */
            console.log(this.bar); //1
        }.bind(this));
    }
}

这里我们取消了中间临时变量_this,而直接在事件绑定中函数参数的末尾使用bind方法,将指向foo对象的this传给band方法,替换掉了事件内的this指向。

另外bind方法不能被覆盖,即

    fun.bind(a).bind(b).bind(c)...
    //只会绑定a,后面b、c的bind均不会生效。

6.5.2 与call/apply比较

与call/apply比较:
1. apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;
2. apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;
3. apply 、 call 、bind 三者都可以利用后续参数传参;
4. bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。

根据上面区别我们就可以根据实际情况选择使用call/apply还是bind的。

这里有更详细的解释http://www.cnblogs.com/coco1s/p/4833199.html

6.5.3 偏函数

使用bind()我们设定函数的预定义参数,然后调用的时候传入其他参数即可:

function list() {
      return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]

6.5.4 配合 setTimeout

一般情况下setTimeout()的this指向window或global对象。当使用类的方法时需要this指向类实例,就可以使用bind()将this绑定到回调函数来管理实例。

function LateBloomer() {
      this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
      window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
      console.log('I am a beautiful flower with ' +this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom();  // 一秒钟后, 调用'declare'方法

6.5.5 绑定函数作为构造函数

绑定函数也适用于使用new操作符来构造目标函数的实例。当使用绑定函数来构造实例,注意:this会被忽略,但是传入的参数仍然可用。

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function() { 
  return this.x + ',' + this.y; 
};

var p = new Point(1, 2);
p.toString(); // '1,2'


var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// 实现中的例子不支持,
// 原生bind支持:
var YAxisPoint = Point.bind(null, 0/*x*/);

var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'

axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true

更多
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

7 函数的属性

7.1 length

  1. length属性表示函数希望接收的命名参数的个数。

7.2 prototype

  1. prototype属性无法枚举,不可使用for-in。

7.3 name

  1. name属性可获取函数名,不管是函数声明还是函数表达式,都可以使用fun.name获取函数的名字。

8 构造函数调用

如果函数或方法调用之前带有关键字new,就构成了构造函数调用。构造函数调用和普通函数调用以及方法调用,在实参处理、调用上下文和返回值方面都有所不同。

  1. 若构造函数无参数,则可直接省略函数后的()。var o = new Object;
  2. 调用构造函数创建新对象,将此对象作为其调用上下文,所以在构造函数中使用this指向新对象。
  3. 构造函数隐式return新对象,若显式使用return返回一个对象,则返回这个对象;若return没有指定返回值,则返回this指向的新对象。
function Fun() { }
var obj = new Fun();
console.log(obj.__proto__ == fun.prototype);    //true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值