高阶函数
一个函数a接受另一个函数b作为自己的参数或者将一个函数c作为返回值返回,则称该函数a为高阶函数,或称为回调函数;
常用高阶函数:one:map :two:forEach :three:filter :four:find/findIndex :five:reduce
函数和方法的区别
==函数function:==
独立的function,那么称之为一个函数
function foo(){} //函数
==方法method:==
当一个函数属于某一个对象时,则我们称这个函数为这个对象的方法
var obj = { foo: function(){} //foo是obj的方法 }
闭包
闭包(closure)由两部分构成,==函数==+==可访问的自由变量==
function foo(){ var name = 'foo' var age = 18; //此时虽然形成闭包,但是v8引擎为了性能,依旧会销毁age function bar(){ console.log(name) } return bar } var fn = foo() fn();
==甚至最简单的函数依旧属于闭包==
<script> var name = 'foo' function foo(){ console.log(name) } </script>
此时依旧构成闭包,虽然
name
声明在go中,但是按照mdn的解释,只要一个函数对其周围状态(lexical environment,词法分析)的引用捆绑在一起,那即是闭包一个普通的函数function,如果==
可以访问
==外层作用域的自由变量,那么这个函数就是一个闭包;从广义的角度:在javascript中任何一个函数都是闭包;
从狭义的角度,javascript中一个函数,如果==
访问
==了外层作用域中的自由变量,那这个函数一定是闭包。
function foo(){
var name = 'foo';
function bar (){
conaole.log(name)
}
return bar
}
var fn = foo();
fn();
/*当代码编译时,
*在执行上下文栈ECS中创建GEC全局执行上下文,并创建vo,此时vo指向go;
*go内部创建foo,在堆内存中分配一块空间,并指向该地址;创建n=undefined
*
*当代码开始执行时,
*在ECS中创建函数执行上下文FEC,并在FEC中创建vo,此时vo指向Ao(活动对象)+parentScopr(GO),
*Ao此时创建name=undefined,创建bar,并在内存中分配一块空间,将bar指向该地址
*bar在堆内存中存在两块内容,一块为作用域,指向parentScope(foo-Ao),另一块为函数执行代码块
*将foo赋值给name,此时name=foo;并将bar函数地址返回给fn,此时fn=bar
*与此同时,foo正式结束,栈出,此时fn指向bar,所以bar不会被销毁;
*bar的vo指向(foo-Ao),所以foo-Ao依旧不会销毁,此时形成内存泄露,bar和foo-ao永远不会被销毁
*/
this
- 函数在调用时,js会默认给this绑定一个值;
- this的绑定和定义的位置没有关系;
- this的绑定和调用方式以及调用的位置有关系;
- this实在运行时被绑定的。
==this绑定规则==
- 默认绑定
//默认绑定window,独立函数调用 function foo(){ console.log(this); //window } foo();
function foo1(){ console.log(this); // window } function foo2(){ console.log(this); //window foo1() //独立函数 } function foo3(){ console.log(this); //window foo2() //独立函数 } foo3() //独立函数
var obj = { foo : function (){ consoel.log(this) } } var bar = obj.foo; //等同于 var bar = function foo(){} bar(); //this => window 依旧为独立函数
function foo(){ console.log(this) } var obj = { foo : foo } var bar = obj.foo bar(); //this => window
function foo(){ function bar (){ console.log(this) } return bar } var fn = foo() fn(); //this => window var obj = { eat : fn } obj.eat(); //this => obj
- 隐式绑定 –> object.fn()
通过某个对象进行调用,必须在对象内部有一个属性对函数进行引用,
如果没有这样的引用,在进行调用时,会报找不到该函数的错误
object对象会被js引擎绑定到fn函数中的this里面
function foo(){console.log(this)} var obj = {foo:foo} obj.foo(); //this => obj
var obj1 = {foo:function (){console.log(this)}} var obj2 = {bar:obj1.foo} obj2.bar(); //this => obj2
==函数直接调用和使用call/apply的区别==
function foo(){ console.log(this) } var obj = {} //foo直接调用指向的时全局对象(window) foo(); //this => window //call、apply是可以指定this的绑定 foo.call(obj); //this => obj foo.apply(obj); //this => obj
function sum (num1,num2){ console.log(num1+num2,this) } sum.call('call',20,30,40); //首先指定this,后参数使用逗号分隔即可 sum.apply('apply',[20,30,40]); //首先指定this,后参数放在数组中进行传参
- 显示绑定
call和apply在执行函数时,是可以明确的绑定this,这个绑定规则被称为显示绑定
function foo(){ console.log(this) } var newFoo = foo.bind('aaa') newFoo(); //this => 'aaa' 默认绑定和显示绑定bind冲突,优先级高的为bind
- new绑定
// 我们通过一个new关键字调用一个函数时(构造器,构造函数),这个时候this指向构造器创建出来的对象 // this => 创建出来的对象 function Person(){ this.name = name } var p1 = new Person('hi') // this => p1 console.log(p1.name)