函数
函数:即一组语句,它们是 JS 的基础模块单元,用于代码复用,信息隐藏和组合调用。 编程:什么为编程?即把一组需求分解成一组函数和数据结构的技能。
函数对象
函数就是对象,对象是键值对的集合,并且隐式连接到原型对象。
function Foo ( ) { }
var poo = new Foo ( ) ;
console. log ( poo. __proto__ === Foo . prototype) ;
console. log ( poo. __proto__ . constructor) ;
console. log ( Foo . prototype. constructor) ;
函数对象在创建时,都配有一个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) ;
myObj. getVal ( 1 ) ;
console. log ( myObj. val) ;
this指向被调用的方法的对象,通过this访问对象,从而取值或修改对象。
函数调用模式
var add = function ( a, b ) {
return a + b
}
var sum = add ( 3 , 4 )
当函数以普通函数被调用时,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) ;
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 ) ) ;
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中。
给类型增加方法
Function . prototype. method = function ( name, func ) {
this . prototype[ name] = func;
return this ;
} ;
Number. method ( 'integer' , function ( ) {
return Math[ this < 0 ? 'ceil' : 'floor' ] ( this ) ;
} ) ;
console. log ( ( - 10 / 3 ) . integer ( ) , ( 10 / 3 ) . integer ( ) ) ;
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 , '左边' , '中间' , '右边' ) ;
function fibonacci ( n ) {
if ( n === 0 || n === 1 )
return n;
return fibonacci ( n- 1 ) + fibonacci ( n- 2 ) ;
}
console. log ( fibonacci ( 10 ) ) ;
作用域
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 ) ) ;
var add_the_handlers = function ( nodes ) {
var i;
for ( i = 0 ; i < nodes. length; i += 1 ) {
nodes[ i] . onclick = function ( e ) {
console. log ( i) ;
}
} ;
} ;
var add_the_handlers = function ( nodes ) {
var i;
var alertIndex = function ( index ) {
return function ( e ) {
console. log ( index) ;
} ;
} ;
for ( i= 0 ; i< nodes. length; i+= 1 ) {
nodes[ i] . onclick = alertIndex ( i) ;
}
} ;
回调
把函数做为参数传递给另一个函数就是回调 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 ( ) ;
如上方示例用来产生一个无法影响内部 prefix 和 seq 安全的序列号。
级联
套用