Function对象
Function对象:一切(引用类型)都是对象,对象是属性的集合
undefined, number, string, boolean属于简单的值类型,不是对象。剩下的一切都是对象,包括函数、数组、对象、null、new Number(10)都是对象。他们都是引用类型。
判断一个变量是不是对象非常简单。值类型的类型判断用typeof,引用类型的类型判断用instanceof。
1、arguments对象:
①重载概念:程序中可定义多个相同函数名,不同参数列表的函数,调用者不必区分每个函数的参数,在执行时,程序根据传入的参数个数,自动判断选择哪个函数执行。
②js语法不支持重载!但可用arguments对象模拟重载效果*
arguments对象:函数对象内,自动创建的专门接收所有参数值得类数组对象。
arguments[i]: 获得传入的下标为i的参数值
arguments.length: 获得传入的参数个数!
即使定义了参数变量,arguments对象同样会收到所有参数值
③例:function a(){
if(arguments.length==1){
//如果传入一个参数,求平方
alert(arguments[0]*arguments[0]);
}else if(arguments.length==2){
//如果传入两个参数,求和
alert(arguments[0]+arguments[1])
}}a(3);a(5,5); //输出:9 10
2、函数对象
创建函数对象时:同时创建2个对象:
函数对象:函数的定义
作用域链对象:保存了函数对象可用变量的位置的对象(栈)
默认第一项指向window对象
调用函数时:又会创建1个新对象:
活动对象:专门保存局部变量的对象
在作用域链对象中追加指向活动对象的引用
调用后:作用域链中活动对象的引用出栈
活动对象因无人引用而释放
3、匿名函数:定义时,不指定函数名的函数
何时使用:2大用途:
① 匿名函数自调:定义完,立刻执行
执行完立刻释放
何时使用:只有确定函数只执行一次时!
如何自调:(function(参数){
函数体
})(参数值);
自调:定义在哪儿,就在哪儿执行,不提前
② 匿名函数回调:将函数作为对象传递给另一个函数
由另一个函数自主决定在需要时调用
何时使用:只要将一个函数对象传递给其他方法调用时
如何回调:直接将匿名函数的声明传入另一个函数中。
4、闭包:
问题:全局变量和局部变量的缺陷
全局变量:容易全局污染
局部变量:无法共享,不能长久保存
闭包好处:即反复使用局部变量,又避免全局污染, 就要用闭包
解决:3步:闭包三特点:
① 定义外层函数,封装被保护的局部变量
② 定义内层函数,执行对外层函数局部变量的操作
③ 外层函数返回内层函数的对象,并且外层函数被调用,结果被保存在全局变量中
标准的闭包写法
function outer(){ //定义外层函数
var n=1; //封装被保存的局部变量
function inner(){ //定义内层函数
return n++;} //执行对外层函数局部变量的操作
return inner; //外层函数返回内层函数的对象
}
var getNum=outer(); //外层函数被调用
getNum();
例:
function add() { //定义外层函数
var x = 1; //封装被保存的局部变量
return function() { //外层函数返回内层函数的对象,定义内层函数,两步一起写
console.log(++x); //执行对外层函数局部变量的操作
};
}
var num1 = add(); //外层函数返回内层函数的对象
var num2 = add(); //外层函数返回内层函数的对象
num1(); //输出2,
num1(); //输出3,
num2(); //输出2,
例:下面这段代码想要循环延时输出结果 0 1 2 3 4,请问输出结果是否正确,如果不正确请说明为什么,并修改循环内的代码使其输出正确结果
for (var i = 0; i < 5; ++i) {
setTimeout(function() {
console.log(i + " ");
}, 100);
}
原因: js 运行环境为单线程,setTimeout 注册的函数需要等到线程空闲时才能执行,此时 for 循环已经结束,i 值为 5,又因为循环中 setTimeout 接受的参数函数通过闭包访问变量 i,所以 5 个定时输出都是 5。
修改方法:将 setTimeout 放在立即执行函数中,将 i 值作为参数传递给包裹函数,创建新闭包。就会保护每个不同的i值
for (var i = 0; i < 5; ++i) {
(function(i) { //定义外层函数
setTimeout(function() { //定义内层函数,并且参数i就是需要被保存的局部变量
console.log(i + " "); //对外层局部变量进行操作
}, 100); //setTimeout()本身就是回调函数,相当于外层函数返回内层函数的对象
})(i); //立即执行函数,属于自己调用自己,就是外层函数被调用
}
输出结果为: 0 1 2 3 4
5、 面向对象:在程序中都是用一个对象来描述现实中一个具体的东西。
现实中的一个东西都包含属性和功能:
属性:描述一个东西特点的变量,一个值
功能:东西可以执行的操作
什么是对象:封装多个数据和方法的存储空间
什么是自定义对象:封装现实中一个东西的属性和功能的存储空间。
现实中东西的属性会成为对象中的属性变量。
现实中东西的功能,会成为对象中的方法(函数)
6、 创建对象
①对象直接量
var obj={"属性名":值,
... : ...,
"方法名" : function(){ ...this.属性名... }
}
② var obj=new Object(); //创建一个空对象
obj.属性名=值;
obj.方法名=function(){...this.属性名...}
③ 利用构造函数*反复*创建*相同结构*的对象共2步:
构造函数:描述一类对象结构的特殊函数
第一步: 定义构造函数
function 构造函数名|类型名(属性参数1,.....){
this.属性名=属性参数1;
//在当前正在创建的对象中添加一个属性名
//赋值为属性参数1的值
...
this.方法名=function(){
...this.属性名...
}
}
第二步: 利用构造函数创建对象:
var obj=new 构造函数名|类型名(属性值1,...);
7、访问对象的属性与方法
属性:如何访问属性:2种:obj.属性名 obj["属性名"]
访问对象中不存在的属性(访问数组中不存在的下标): 不会出错,返回undefined
强行给不存在属性赋值,不报错!js会自动创建同名属性
如何判断某个对象是否包含指定成员:3种
①obj.hasOwnProperty("成员名")
② "属性名" in 对象
如果找到,返回true,否则返回false!
③ 直接使用obj.属性名作为条件:
arr.indexOf!==undefined
如果不包含,返回undefind-->false
如果包含,返回值或function-->true
何时省略:判断方法是否存在时,可省略!==
如果确定属性值一定不是null,0,"",NaN
也可省略
方法:如何在方法中,访问当前对象自己:
this关键字:运行时,指代正在*调用*方法的对象
(.前的对象)
this本质是window下唯一的一个指针,指向当前正在调用方法的对象
在方法内访问当前对象自己的属性,必须用this.属性名
this和定义在哪儿无关!仅和调用时使用的当前对象有关
如果无主的调用或赋值,默认this都是window!
改变this的指向有call()、apple()和 bind(),想详细了解请看我转载的另一篇文章
8、JavaScript原型与原型链
知识较多较杂,梳理不清楚,推荐大家看我转载的一篇文章《详解JavaScript原型链》
这里面说的提别清楚