一:函数
为什么使用函数
函数对任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,
而且可以在任何地方、任何时候调用执行。在javascript里,函数即对象,程序可以随意操控它们。
函数可以嵌套在其他函数中定义,这样它们就可以访问它们被定义时所处的作用域中的任何变量,
它给javascript带来了非常强劲的编程能力。
函数本身也是对象
函数的声明
1、普通函数声明
function funcname(arg1 ,arg2 …,argn){
statement;
}
通常来说函数的声明会有一个返回值,如果没有设置return,
该函数默认返回未undefined,如果设置,将返回该值。执行函数后会返回该值。
function abc(){
var s=3+4;
return s;
}
var s1=abc();//s1===7;
这样定义的函数是当前标签script创建时被放入堆中,
该函数在这个标签的任意位置都可以执行,当然也可以在下一个script标签中执行
2.匿名函数声明
var box=function(num1,num2){
retrun num1+num2;
}
这是匿名函数声明,声明函数的时候没有赋予名称,
但是函数声明好以后却赋值给了box,这里注意box并不是num1+num2的值,而是function定义的这个匿名函数。
匿名函数在声明前不可被调用,只有在声明后才可被调用。
3、对象的方法声明方式,这个函数被限定在对象中,使用对象才可以调用该函数
也就说这个函数成了私有函数。
var obj={
name:”zhangsan”,
fire:function(num1,num2){
var s=num1+num2;
return s;
}
}
3、Function构造函数
使用Function构造函数
var box=new Function(‘num1’,‘num2’,‘retun num1+num2’);//num1,num2参数,最后的字符串是函数体
PS:第三种方式我们不推荐,因为这种语法会导致解析两次代码
(第一次解析常规JS代码,第二次是解析传入构造函数中的字符串),从而影响性能,
但构造函数还有一个另外的功能, 就是可以处理服务器发过来的字符串指令,当服务器不能用jsonp来
请求时,用Ajax请求,但是服务器回传的字符串指令就可以用构造函数的方式来处理。
二:函数的执行
函数执行 :函数名()
执行后,可以完成函数的代码内容,如果函数内有return 值,这时候执行后会返回该值。
function abc() {
return 3+4;
}
var s=abc();
如何没有return,则执行完所有代码
函数的独立执行
函数自身是可以独立执行的,并且也可以把独立执行的结果赋值给一个变量。
var s=0
(function(){
s=4+5;
})()
匿名函数自己执行
var s=(function(){
return 4+5;
})();
匿名函数赋值
注意匿名函数用小括号括住,最后再执行小括号。
注意,除了匿名函数可以独立执行,实名函数也是可以独立执行的,
不过这种独立执行就不能在该函数中添加参数了,并且匿名函数,也只能在此执行一次,
不能多次调用,显而易见的好处是,该函数内的变量统统是私有变量,避免了变量污染。
call和apply,bind(重新定义this指向。)
函数名.call(thisObj,arg1,arg2,argN)
thisObj(可选项)。将被用作当前对象的对象。arg1, arg2, argN 可选项。将被传递方法参数序列。
call 方法可以用来代替另一个对象调用一个方法。
call 方法可将一个函数的对象改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作thisObj。
说明白一点其实就是更改对象的内部指针,即改变对象的this指向的内容。
函数名.apply
apply:apply(thisObj,[argArray]),应用某一对象的一个方法,用另一个对象替换当前对象。
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj,
并且无法被传递任何参数
函数名.bind
bind(thisObj,arg1,arg2,arg3),相比于call和apply,bind是先绑定后执行,
在函数执行的时候执行bind。
thisObj即为函数的this指向,如果arg1是数组,会被当做一个数组参数赋值给参数。
call和apply是执行函数,将call和apply的第一个参数带入到函数中替代原函数中this,
函数中如果没有this,这种替代就变成无意义的内容,混入对象替代函数内的this。
如果call和apply的第一个参数是null,原函数中this表示仍然是原来的this,不是null
一旦参数是多个,我们通常使用参数作为数组使用,这时候使用apply
静态方法一般可以直接使用apply和call来调用执行
但是动态方法必须使用原型方法调用call和apply;
例如: arr.push.apply(null,arr1);//错误,动态方法不能直接调用apply
Array.prototype.push.apply(arr,arr1);//将arr1中的每一项push到arr中,
//等同于concat
三:this
阮一峰老师:this它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。
这句话看似平常,可是要非常注意三个字:“运行时”,这说明this关键字只与函数的执行环境有关,
而与声明环境没有关系。也就是这个this到底代表的是什么对象要等到函数运行时才知道,
有点类似函数定义时的参数列表只在函数调用时才传入真正的对象。
this关键字虽然会根据环境变化,但是它始终代表的是调用当前函数的那个对象。
这就引出了JS中函数调用的问题。在JS中调用函数的模式可以分为4种:
方法调用模式、函数调用模式、构造器调用模式、apply调用模式。
这些模式在如何初始化关键参数this上存在差异。
1、方法调用模式
当函数被保存为一个对象的属性时,它就可称为这个对象的方法。
当一个方法被调用时,this被绑定到这个对象上。如果调用表达式包含一个提取属性的动作(. 或 []),
那么它被称为方法调用。例如:
var name = “window”;
var obj = {
name: “test”,
sayName: function() {
console.log(this.name);
}
};
obj.sayName(); //test
sayName函数作为对象obj的方法调用,所以函数体中的this就代表obj对象。
2、函数调用模式
当一个函数并非一个对象的属性时,那么它就是被当做函数来调用的。
在此种模式下,this被绑定为全局对象,在浏览器环境下就是window对象。例如:
ar name = “window”;
function sayName() {
console.log(this.name);
}
sayName();
sayName以函数调用模式调用,所以函数体中的this代表window对象。
3、构造函数模式
如果在一个函数前面加上new关键字来调用,那么就会创建一个连接到该函数的prototype成员的新对象,
同时,this会被绑定到这个新对象上。这种情况下,这个函数就可以成为此对象的构造函数。例如:
function Obj() {
this.name = “test”;
}
var person = new Obj();
console.log(person.name); //test
Obj作为构造函数被调用,函数体内的this被绑定为新创建的对象person。
4、apply调用模式
在JS中,函数也是对象,所有函数对象都有两个方法:apply和call,
这两个方法可以让我们构建一个参数数组传递给调用函数,也允许我们改变this的值。例如:
当以函数调用模式调用sayName时,this代表window;当用apply模式调用sayName,
并给它传入的第一个参数为person时,this被绑定到person对象上。
var name = "window";
var person = {
name: "test"
};
function sayName() {
console.log(this.name);
}
sayName(); //window
sayName.apply(person); //test
sayName.apply(); //window
如果不给apply传入任何参数,则在这里插入代码片this代表window。
apply改变了this的指向。指向了apply中的第一个参数对象
案例:
var name = "window";
function showName() {
console.log(this.name);
}
var person1 = {
name: "test",
sayName: showName
}
var person2 = {
name: "qqh",
sayName: function() {
var fun = person1.sayName;
fun();
}
}
person1.sayName(); //test
person2.sayName(); //window
person1.sayName(); 首先确定这是方法调用模式,对象为person1,
再看sayName被赋值为全局函数对象showName,在showName执行时,
this绑定的是person1,所以结果为”kxy”。
再看第二个执行语句:person2.sayName(); 这还是方法调用模式,对象为person2,
调用的是它的sayName方法。再看sayName函数体,发现函数体最终执行的函数是fun,
fun是用函数调用模式调用的。而fun最终也被赋值为showName函数,
因为fun是用函数调用模式调用的
,所以这里的this绑定为window,结果为”window“。
this中知识点整理参考:https://www.cnblogs.com/kongxy/p/4581223.html
四:函数的删除
当函数不再使用时,就需要删除,函数也是对象,如果不删除,它将常驻内存中,
如果该函数不再使用就可以使用删除彻底清除掉该函数。
但是只有函数是匿名定义的或者通过构造函数创建的才可以被删除。通过delete或者null
全局的函数是不能删除的,但是可以赋值为null
对象中函数可以通过delete或者null删除
五:参数和return
函数参数
参数是指由外部传入到函数中的变量,仅作为变量使用,但是该变量可以是任何内容,包括函数。
被传入的参数作为私有变量使用,可以被覆盖掉。
参数在使用通常也可以理解为封闭空间注入需要修改或者处理的内容
通过注入参数,可以使函数成为一个独立工厂处理空间,也使函数发挥更大的作用,增强复用性。
降低与外界的耦合度。
参数是无限的数量(例如Math.max)ES5就不再函数中写参数,而处理arguments
而ES6 可以通过 …arg这种写法来罗列无限参数
arguments对象
arguments是一个函数参数的类数组集合,
arguments对象的length属性可以得到参数的数量
arguments.callee 当前参数对应的函数
arguments.callee.caller 当前参数对应函数的父函数
如果函数是一个全局函数,就没有caller
return
return 语句会终止函数的执行并返回函数的值。return 是javascript里函数返回值的关键字,
一个函数内处理的结果可以使用return 返回,这样在调用函数的地方就可以用变量接收返回结果。
return 关键字内任何类型的变量数据或表达式都可以进行返回,甚至什么都不返回也可以
return 也可以作为阻止后续代码执行的语句被使用,跳出函数从而不执行下面的代码。
function abc(){
if(bool) return;
}
这样可以有效的控制语句在一定的条件下执行,不过一定要与break区分,
break是用在条件当中,跳出的也仅仅是条件和循环,但是return 却可以跳出函数,
仅仅是针对函数使用,如果没有函数是不能使用return的。
return可以返回任何值,但只能返回一个值,可以通过返回一个数组或对象返回多个元素。
也可以返回函数体,等等
工厂模式和单例模式都是通过return来完成。
function fun1(){
return {
a:1,
b:2,
fun2:function(){
console.log(this.a+this.b);
}
}
}
var obj=fun1();
obj.fun2();
这是自定义函数,然后执行以后赋值给obj,然后才去执行fun2