js 函数


基本类型参数是做为值类型传入到函数的,传入的是值本身,如果函数体对该传入值进行了操作该变了该值,
这种改变将不会影响全局或者该函数的调用。
function square(number) {
  return number * number;
}
而当非基本类型的值比如Array或者用户自定义的对象类型作为参数传入函数时,函数体对该对象的属性进行了操作
这种操作带来的变化将在函数体外仍然可见。
function myFunc(theObject){
theObject.make = "BMW";
}
var mycar = {make: "Honda", model: "Accord", year: 1998};
var x, y;


x = mycar.make; // x gets the value "Honda"


myFunc(mycar);
y = mycar.make; // y gets the value "BMW"
                // (the make property was changed by the function)



也就是说值类型传入函数后,对其进行的操作不会影响到函数体外。
而非基本类型传入函数后,函数体对其的操作可以被带到函数体外,影响到调用该函数的范围甚至是全局。


函数除了以定义的句法定义外还可以通过表达式的形式定义:表达式左边定义一个函数名称变量,右边使用匿名函数体定义。
var square = function(number){ return number*number; }
var x = square(4); //x 的值为 16


其实 在右边完全可以为函数表达式定义名称,该名称可以在函数体内部使用,它指向本身。
var factorial = function fac(n){ return n<2 ? 1: n*fac(n-1) };
console.log(factorial(3));


函数表达式在我们想将一个函数作为参数传入另外一个函数时非常有用。
function map(f,a) {
  var result = [], // Create a new Array
      i;
  for (i = 0; i != a.length; i++)
    result[i] = f(a[i]);
  return result;
}
上面map函数的定义中,使用了一个匿名函数f作为其第一个参数。注意for循环的定义。
调用:
map(function(x){return x*x*x },[0,1,2,5,10]); //返回 [0,1,8,125,1000]


在javascript中一个函数可以根据条件去定义。
var myFunc;
if (num == 0){
  myFunc = function(theObject) {
    theObject.make = "Toyota"
  }
}


另外我们还可以使用函数的构造器来在运行时从一个字符串创建函数,很像eval()
方法method是一种作为对象属性的函数Function。


函数的调用:
函数必须在一定的范围scope中被调用,但是函数的声明位置必须被提升。
console.log(square(5));
function square(n){ return n*n }
一个函数能够使用的范围scope就是该函数被声明时的范围,如果该函数被声明在最顶部,则其范围是整个应用程序。
注意上面说的应用范围必须是通过函数定义语法声明的,而非表达式等方式声明的时候。
如下代码将不能工作,因为函数变量在调用时还没有被声明。
console.log(square(5));
square = function (n) {
  return n * n;
}


一个函数可以调用它自己。
function factorial(n){
  if ((n == 0) || (n == 1))
    return 1;
  else
    return (n * factorial(n - 1));
}


var a, b, c, d, e;
a = factorial(1); // a gets the value 1
b = factorial(2); // b gets the value 2
c = factorial(3); // c gets the value 6
d = factorial(4); // d gets the value 24
e = factorial(5); // e gets the value 120


函数范围:
在函数体内部定义的变量在函数体外部是无法访问的,因为这些变量的工作范围只是该函数体。
而函数本身访问其内部定义的所有变量和函数,换句话说一个定义在全局范围内的函数可以方法全局范围内的所变量和函数。
如果一个函数定义在另一个函数体内,则该内函数可以访问所有其父函数体内定义的以及该父函数能够访问的变量和函数。
// The following variables are defined in the global scope
var num1 = 20,
    num2 = 3,
    name = "Chamahk";


// This function is defined in the global scope
function multiply() {
  return num1 * num2;
}


multiply(); // Returns 60


// A nested function example
function getScore () {
  var num1 = 2,
      num2 = 3;
  
  function add() {
    return name + " scored " + (num1 + num2);
  }
  
  return add();
}


getScore(); // Returns "Chamahk scored 5"


范围和函数堆栈循环:
一个函数可以通过三种方式调用自身:函数名字,argument.callee,一个指向函数本身的内部定义变量。
var foo = function bar(){
//statements go here
};
则在该函数体内bar(),arguments.callee(),foo() 是等价的。
一个函数在其函数体内部调用自身,这类函数被称为recursive function 递归函数。
var x = 0;
while (x < 10) { // "x < 10" is the loop condition
   // do stuff
   x++;
}
可以用递归函数来定义:
function loop(x) {
  if (x >= 10) // "x >= 10" is the exit condition (equivalent to "!(x < 10)")
    return;
  // do stuff
  loop(x + 1); // the recursive call
}
loop(0);


下面函数获取所有的DOM节点:
function walkTree(node) {
  if (node == null) // 
    return;
  // do something with node
  for (var i = 0; i < node.childNodes.length; i++) {
    walkTree(node.childNodes[i]);
  }
}


类堆行为:
function foo(i){
if(i<0)
return;
console.log('begin:' + i);
foo(i-1);
console.log('end:'+ i);
}
foo(3);


嵌套函数和闭包:
闭包closure 是一个能够包含自由变量和一个绑定这些自由变量的环境的表达式。
因此嵌套函数inner function是一个闭包,这就意味着嵌套函数可以继承包含它的函数的参数和变量。
换句话说,内部函数包含了外部函数的范围。


内部函数只能在父函数体内范围访问。
内部函数构成了一个闭包:内部函数可以使用外部函数的参数和变量,而外部函数不能使用内部函数的参数和变量。


function addSquares(a,b){
function square(x){
return x*x;
}
return square(a)+square(b);
}
a = addSquares(2,3); // returns 13
b = addSquares(3,4); // returns 25
c = addSquares(4,5); // returns 41




function outside(x) {
  function inside(y) {
    return x + y;
  }
  return inside;
}


fn_inside = outside(3); // Think of it like: give me a function that adds 3 to whatever you give it
result = fn_inside(5); // returns 8


result1 = outside(3)(5); // returns 8




变量保留:
一个闭包必须保留其引用过的参数和变量。因为每次调用会潜在的提供不同的参数,外面的每次调用都回创建一个新的闭包。
内存只有在内部的返回值不再被访问时才会清理,所以当我们将一个内部函数返回给某个外部变量时,该闭包的环境对象将会保持。


这个将引用保存到另外一个对象中一样,只不过看起来不是那么明显而已。


多嵌套函数:闭包可以包含多个作用区域,它们会叠加包含其父函数的作用区域。 这叫做scope chaining.
function A(x) {
  function B(y) {
    function C(z) {
      console.log(x + y + z);
    }
    C(3);
  }
  B(2);
}
A(1); // logs 6 (1 + 2 + 3)


命名冲突:当两个参数或者变量在同一个闭包作用域里同名时就会产生命名冲突。
越内层的变量优先级越高,所以最内层的闭包内的变量优先级最高,最外层变量优先级最低。
{inside, outside, global object}




闭包:作为Javascript中最为强大的内容之一,能够使javascript定义嵌套函数并赋予内部函数访问所有外部函数
体中定义的函数和变量的权限。而外层函数却无法访问内层函数定义的变量和函数,从而为这些内部定义的变量和函数提供了安全保障。
由于内层函数对外层函数定义的变量和函数成员的访问,使得如果内层函数的生命周期大于外层函数时这些变量和函数比定义它们的外层函数寿命更长。
当内部函数以某种方法在外层函数作用范围之外可用时,闭包也就被创建了。
它能够让外层函数的某些变量和函数成员的生命周期长于外层函数本身的生命周期。


var pet = function(name) {   // The outer function defines a variable called "name"
  var getName = function() {
    return name;             // The inner function has access to the "name" variable of the outer function
  }
  return getName;            // Return the inner function, thereby exposing it to outer scopes
},
myPet = pet("Vivie");
   
myPet();                     // Returns "Vivie"




一个包含对外部函数的成员变量进行处理方法的内部对象被返回。
var createPet = function(name) {
  var sex;
  
  return {
    setName: function(newName) {
      name = newName;
    },
    
    getName: function() {
      return name;
    },
    
    getSex: function() {
      return sex;
    },
    
    setSex: function(newSex) {
      if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}
var pet = createPet("Vivie");
pet.getName();                  // Vivie


pet.setName("Oliver");
pet.setSex("male");
pet.getSex();                   // male
pet.getName();                  // Oliver




var getCode = (function(){
  var secureCode = "0]Eal(eh&2";    // A code we do not want outsiders to be able to modify...
  
  return function () {
    return secureCode;
  };
})();


getCode();    // Returns the secureCode


注意如果我们再闭包函数中定义了一个跟外部范围中定义的变量同名的变量,那么闭包将没有办法在处理该变量。
var createPet = function(name) {  // Outer function defines a variable called "name"
  return {
    setName: function(name) {    // Enclosed function also defines a variable called "name"
      name = name;               // ??? How do we access the "name" defined by the outer function ???
    }
  }
}




使用参数对象 arguments
一个函数的参数被维护在一个类数组的对象里,我们可以在函数内部解析出传入参数:arguments[i], i是从0开始的整数字,长度为arguments.length
在我们不清楚函数传入参数数量的时候,可以通过arguments.length来确认,然后通过arguments对象来访问它们。


function myConcat(separator) {
   var result = "", // initialize list
       i;
   // iterate through arguments
   for (i = 1; i < arguments.length; i++) {
      result += arguments[i] + separator;
   }
   return result;
}
我们可以传入任何数量的参数到函数,它会连接它们到一个字符串。
// returns "red, orange, blue, "
myConcat(", ", "red", "orange", "blue");


// returns "elephant; giraffe; lion; cheetah; "
myConcat("; ", "elephant", "giraffe", "lion", "cheetah");


// returns "sage. basil. oregano. pepper. parsley. "
myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");

注意arguments是类数组对象而非数组,类数组是因为它有index和length属性,但是它没有数组的其它处理方法。




函数参数:
从ES6开始,将有 default参数和rest参数
默认参数:在js中一个函数的默认参数是undefined,但是有些时候需要我们为其设置一个不同的默认值,这时default参数就派上用场了。
过去我们为函数设置默认参数值主要是在函数体开始判断传入参数是否为undefined,如果是就给它赋予默认的其它值。
function multiply(a,b){
return a*b;
}
上面函数如果我们不给b传值,那么函数会认为b的默认值是undefined, 其返回的计算结果为NaN,非数字值。
传统的做法是:
function multiply(a, b) {
  b = typeof b !== 'undefined' ?  b : 1;


  return a*b;
}
在ES6后我们可以直接在参数上设置默认值:
function multiply(a, b = 1) {
  return a*b;
}


multiply(5); // 5




剩余参数:用于表示一个无穷数的参数作为一个数组。
箭头函数 =>
function multiply(multiplier, ...theArgs) {
  return theArgs.map(x => multiplier * x);
}


var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]


箭头函数  =>
也叫胖箭头函数,是函数表达式的简洁写法,它灵活的绑定到this值上,它总是匿名的。
var a = [
  "Hydrogen",
  "Helium",
  "Lithium",
  "Beryl­lium"
];


var a2 = a.map(function(s){ return s.length });


var a3 = a.map( s => s.length );




this词法:在箭头函数之前,每个新函数都会定义一个自己的this值。
新对象是指 构造器,在严格函数调用里是undefined,当函数作为对象方法调用时是上下文对象。
这给面向对象编程带来了困扰。
function Person() {
  // The Person() constructor defines `this` as itself.
  this.age = 0;


  setInterval(function growUp() {
    // In nonstrict mode, the growUp() function defines `this` 
    // as the global object, which is different from the `this`
    // defined by the Person() constructor.
    this.age++;
  }, 1000);
}


var p = new Person();






这里一个绑定函数被定义,所以一个合适的this值被传递给了growUp()函数。
function Person() {
  var self = this; // Some choose `that` instead of `self`. 
                   // Choose one and be consistent.
  self.age = 0;


  setInterval(function growUp() {
    // The callback refers to the `self` variable of which
    // the value is the expected object.
    self.age++;
  }, 1000);
}


通过箭头函数来捕获封闭范围的this值:
function Person(){
this.age = 0;

setInterval(()=>{
this.age++;// |this| 属性只想person对象
},1000);
}


var p = new Person();




预定义函数:
eval():执行一段脚本代码并返回一个字符串
uneval():创建一个表示对象源代码的字符串
isFinite():全局函数,判断传入的值是否为一个无穷数,如果需要首先会将传入内容转换为数字,然后判断。
isNaN():判断一个只是否为NaN,Number.isNaN(),或者用typeof
parseFloat():将一个字符串参数转换为浮点型数字
parseInt():将一个字符串参数转换为整型数字
decodeURI():解码由encodeURIComponent创建的统一资源标识,类似一个简单的路由。
encodeURI():通过替换特殊字符创造一个UTF-8编码的统一资源标识。
encodeURIComponent(): 同上
escape():判断一个字符串是否已经替换了特殊字符。
unescape():判断一个字符串是否已经将特殊字符换回。

转载于:https://my.oschina.net/u/924064/blog/611325

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值