JavaScript语言精粹学习笔记---函数

函数

  • 函数:即一组语句,它们是 JS 的基础模块单元,用于代码复用,信息隐藏和组合调用。
  • 编程:什么为编程?即把一组需求分解成一组函数和数据结构的技能。

函数对象

  • 函数就是对象,对象是键值对的集合,并且隐式连接到原型对象。
 function Foo() {} //构造函数
 var poo = new Foo(); //实例化一个对象
 console.log(poo.__proto__ === Foo.prototype); //true ,说明是指向同一个原型对象
 console.log(poo.__proto__.constructor); //Foo()
 console.log(Foo.prototype.constructor); //Foo()
 
  • 函数对象在创建时,都配有一个prototype 属性[Foo.prototype],它的值是一个拥有constructor属性,且属性值为该函数的对象[Foo.prototype.constructor==Foo]

函数字面量

  • 通过函数字面量来创建函数
	var add = function (par1, par2) {
		return par1 + par2;
};

调用

  • 在JavaScript中,一共有四种调用模式
    方法调用模式
    函数调用模式
    构造器调用模式
    apply调用模式
  • 除了声明时定义的形参,每个函数还另外接受两个特殊参数this和arguments
  • 参数this的值取决于调用模式
方法调用模式
var myObj = {
  val: 0,
  getVal: function (inc) {
    this.val += typeof inc === "number" ? inc : 1;
  },
};
myObj.getVal();
console.log(myObj.val); //1

myObj.getVal(1);
console.log(myObj.val); //2
  • this指向被调用的方法的对象,通过this访问对象,从而取值或修改对象。
函数调用模式
var add = function(a, b) {
  return a + b
}
var sum = add(3, 4) //7
  • 当函数以普通函数被调用时,this指向全局。一个简单的解决方案是将内部函数的this赋值给一个新的变量that,此时内部函数可以通过that访问this。
构造器调用模式
  • 如果在一个函数前面加上 new 关键字调用,那么底层是会创建一个连接到该函数 prototype 成员的新对象,同时绑定 this 至新对象。
  • 函数若通常使用 new 来结合调用,那么它就被称之为构造器函数,这类函数通常以首字母大写区分。
Apply调用模式
var add = function(a, b) {
  return a + b
}
var arr = [3, 4]
var sum = add.apply(null, arr)
console.log(sum); //7
  • apply 方法可以构建一个参数数组传递给调用函数,并且可自由选择 this 的指向。
  • apply 中通常第一个参数为 this 绑定的值,第二个为参数数组。

参数

  • 当函数被调用时,都会拥有一个 arguments数组,它里面包含了所有被调用时,传递给它的参数。
var sum = function () {
  var i = 0;
  sum = 0;
  for (i; i < arguments.length; i++) {
    sum += arguments[i];
  }
  return sum;
};
console.log(sum(1, 3, 4, 6, 7, 10)); //31
  • arguments 并不是一个真正的数组,而是一个类数组对象,arguments是一个拥有 length 属性的特殊对象,但它不具备任何数组方法。

返回

  • 当函数被调用时,从起始语句执行到遇到函数体 } 时结束,然后移交控制权至调用该函数的程序。
  • retrun 语句可使函数结束执行提前返回,若无指定返回值,则返回 undefined。
  • js 中大部分函数在未设置 return 值时都会默认返回一个 underfined。
  • 如果是构造器调用模式,返回值如果不是一个对象,那么就返回this

异常

var add = function(a,b){
if(typeof a !== 'number' || typeof b !== 'number'){
  throw {
    name:'TypeError',
    message:'add needs numbers'
  };
};
  return a + b;
};

try {
  add('',3);
} catch(e) {
  console.log(e);
}
  • throw语句中断函数,抛出一个至少包含name和message的exception对象,最后传递到catch中。

给类型增加方法

// 给所有函数添加一个method方法
Function.prototype.method = function(name,func){
  this.prototype[name] = func;
  return this;
};
// 给Number函数添加一个integer方法
Number.method('integer',function(){
  return Math[this<0?'ceil':'floor'](this);
});
console.log((-10/3).integer(),(10/3).integer());//-3,3

String.method('trim',function(){
  return this.replace(/^\s+|\s+$/,'')
});
console.log('    neat   '.trim());
  • 通常避免混淆,可以利用 hasOwnProperty 来判断是否是自身属性(非继承)来的。

递归

  • 简单来说:递归就是直接或间接调用自身的一种函数,基本概念分为
var hanoi = function(disc,src,aux,dst){
  if(disc>0){
    hanoi(disc - 1,src,dst,aux);
    console.log('move disc '+disc+'from '+src +' to ' + dst);
    hanoi(disc - 1,aux,src,dst);
  }
};   
hanoi(3,'左边','中间','右边');

// move disc 1from 左边 to 右边
// move disc 2from 左边 to 中间
// move disc 1from 右边 to 中间
// move disc 3from 左边 to 右边
// move disc 1from 中间 to 左边
// move disc 2from 中间 to 右边
// move disc 1from 左边 to 右边
  • 尾递归 一个函数返回自身递归调用的结果
// 定义式 的斐波那契数列计算方式
function fibonacci(n) {
    if(n === 0 || n === 1)
        return n;
    return fibonacci(n-1) + fibonacci(n-2);
}
console.log(fibonacci(10)); //55

作用域

var foo =function(){
  var a=3,b=5;
  var bar = function(){
    var b=7,c=11;
    a +=b+c;
  };
  bar();
};
  • 作用域控制着参数与变量的生命周期。
  • javascript只有函数作用域,但是没有块级作用域。
  • 作用域的好处是,可以使父级函数内部的子级函数访问父级函数里的参数和变量,除了this和auguments。
  • 应尽可能在函数体顶部声明所有可能用到的变量。

闭包

  • 函数内部嵌套函数 包含被引用变量(函数)的对象。
// 闭包 + 缓存对象
const fibonacci = (function () {
  const f = {}
  return function(n) {
    if(n === 0 || n === 1) {
      return n
    }
    if(f[n-2] === undefined) {
      f[n-2] = fibonacci(n-2)
    }
    if(f[n-1] === undefined) {
      f[n-1] = fibonacci(n-1)
    }
    return f[n] = f[n-1] + f[n-2]
  }
})()
console.log(fibonacci(10)); //55
  • 使用闭包来缓存斐波那契数列
var add_the_handlers = function(nodes) {
  var i;
  for (i = 0; i < nodes.length; i += 1) {
    //Nodes后面的i和var i是在一个作用域里面的.所以值一直在变
        nodes[i].onclick = function(e) { 
            console.log(i);//这里只是声明了一个函数,i一直只是一个引用,值根本不会变.只有在执行的时候才会去调用i变量.那个时候i已经是Length了
        }
    };
};

var add_the_handlers = function(nodes){
    var i;
    //整个alertIndex就是一个闭包,他返回一个其名函数,接收一个e的参数..但是他的代码块,则是返回index这个参数.而这个参数,是每次循环的时候就固定赋值的    
    var alertIndex = function(index){
        return function(e){
            console.log(index);
        };
    };
    
    for(i=0;i<nodes.length;i+=1){
        nodes[i].onclick = alertIndex(i);//这里是直接调用方法,...立即就执行了这个方法,一共扫行了length次,就不会出现上面那种情况了
    }
};
  • 循环内部不要创建函数做无用的计算。

回调

  • 把函数做为参数传递给另一个函数就是回调
  • js是单线程的,但是我们可以发起异步请求。

模块

  • 模块一般是:一个定义私有变量和函数的函数,利用闭包创建可访问私有变量和函数的特权函数,最后把这个函数保存到公共可访问的地方。
  • 模块可以摒弃大量全局变量使用,便于应用程序的封装和构造。
/**根据书中的示例创建*/
var serial_maker = function () {
  var prefix = "";
  var seq = 0;
  return {
    set_pre: function (p) {
      prefix = String(p);
    },
    set_seq: function (s) {
      seq = s;
    },
    gensym: function () {
      var result = prefix + seq;
      seq += 1;
      return result;
    },
  };
};
var seqer = serial_maker();
seqer.set_pre("x");
seqer.set_seq("1");
var unique = seqer.gensym(); // 'x1'
  • 如上方示例用来产生一个无法影响内部 prefix 和 seq 安全的序列号。

级联

  • 函数返回this就是级联。

套用

  • 就是让函数和他的参数构成一个新的函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值