JS高级(作业域链,闭包,面向对象)
作用域链
定义
- 变量在当前环境now、内部环境f1、内部深层环境f2/f3....都起作用的现象形成了一个链条,这个链条就称为变量的"作用域链"
<script type="text/javascript">
var title="链条“;
console.log("now"+title);
function f1(){
console.log("f1"+title);
function f2(){
console.log("f2"+title);
function f3(){
console.log("f3"+title);
}
f3();
}
f2();
}
f1();
</script>
作用域链的作用
- 变量必须“先声明、后使用”
函数可以“先使用、后声明”,原因是函数有“预加载”过程(函数声明先于其他执行代码进入内存)。本质还是函数的声明在前,使用在后。
<script type="text/javascript">
f1();
function f1(){
console.log("f1"+title);
}
</script>
- 内部环境可以访问外部环境的变量,反之不然
- 变量的作用域是声明时决定的,而不是运行时
闭包
什么是闭包
- 闭包就是一个函数,两个函数彼此嵌套,内部函数就是闭包 形成闭包条件是内部函数需要通过return给返回出来.
<script type="text/javascript">
function f1(){
var name="tom";
var age=18;
function f2(){
console.log("名字:"+name+",年龄:"+age);
}
return f2;
}
var ff=f1();//这就是一个闭包,ff与f2共同指向一个function
ff();//名字:tom,年龄:age
</script>
- 解释
f1()调用完成后,垃圾回收器会回收name和age,但是因为ff又去指向function,这样function内部的age和name仍然存在,并且与外部变量无关
闭包使用规则
- 同一个闭包机制可以创建多个闭包函数出来,它们彼此没有联系,都是独立的。 并且每个闭包可以保存自己个性化的信息。
<script type="text/javascript">
function f1(){
var name="tom";
var age=18;
function f2(){
console.log("名字:"+name+",年龄:"+age);
}
return f2;
}
var ff1=f1();
var ff2=f2()
var ff3=f3();
</script>
闭包案例
- 闭包生成数组元素
<script type="text/javascript">
var arr=new Array();
for(var i=0;i<4;i++){
arr[i]=function () {
console.log(i);
return i;
}
}
arr[2](); //4
arr[1](); //4
arr[0](); //4
arr[3](); //4
</script>
- 使用闭包
<script type="text/javascript">
var arr=new Array();
for(var i=0;i<4;i++){
arr[i]=f1(i);
}
function f1(n) {
function f2() {
console.log(n)
}
return f2;
}
arr[0](); //0
arr[1](); //1
arr[2](); //2
arr[3](); //3
</script>
- 闭包事件操作
<script type="text/javascript">
window.onload=function () {
var cars=document.getElementsByTagName('li');
//可以利用闭包给每个元素设置独立的函数处理
//并且函数内部也有独特的下标信息供访问
for(var i=0;i<3;i++){
cars[i].onmouseover=over(i);
cars[i].onmouseout=out(i);
}
var col=['red','green','blue'];
function over(n) {
function f2() {
cars[n].style.backgroundColor=col[n];
}
return f2;
}
function out(n) {
function f2() {
cars[n].style.backgroundColor="";
}
return f2;
}
}
</script>
面向对象操作
① 字面量方式创建
<script type="text/javascript">
var dog={name:'旺财',age:5,hobby:function () {
console.log("看家护院")
}};
//对已有成员丰富其对象
dog.color="yellow";
dog['weight']=80;
dog.run=function () {
console.log("在跑步");
}
//访问成员
console.log(dog.name);
dog.hobby();
dog['run']();
</script>
② 构造函数创建对象
<script type="text/javascript">
function Animal() {
//设置默认成员(通过this引用)
this.name="tom";
this.age=6;
this.run=function () {
console.log("在跑步");
}
}
var cat=new Animal();
console.log(cat);
cat.run();
</script>
③ Object方式创建对象
<script type="text/javascript">
var cat=new Object();
cat.eat="fish";
console.log(cat);
</script>
构造函数与普通函数区别
没有区别,就看使用,new就是构造函数,函数()就是普通函数调用。
函数的各种执行方式
① 普通函数调用
② 构造函数执行new
③ 作为对象的成员方法执行
④ 通过call和apply执行
call和apply可以明显控制变量污染的风险。
call无需声明新的成员出来,就可以直接使用其他函数或方法
<script type="text/javascript">
var cat={name:"tom",climb:function () {
console.log(this.name+"在爬树")
}};
var dog={name:"旺财",age:6};
var wolf={name:"灰太狼"};
cat.climb.call(cat);
cat.climb.call(dog);
</script>
apply()方法与call()方法类似,只是将函数test的所有的参数放在一个数组中而已。即:apply()方法只有两个参数,一个是obj对象,另一个是数组,这个数组中存放的是test函数的所有实参。
- 总结:是为了动态的改变this的指向
this都是谁
① 在函数/方法里边 代表调用该函数/方法的当前对象
② 在事件中,代表元素节点对象
divnode.onclick = function(){
alert(this.value);
}
③ 代表window
④ 可以任意代表其他对象
在call和apply使用的时候,可以任意设置被执行函数内部this的代表
获取构造器
-
构造器:使用什么元素实例化的对象,元素就称为该对象的构造器
-
对象.constructor; //获得构造器