简述
js中函数的应用占有非常重要的地位,可以单纯的将一部分逻辑封成一个函数,也可以创建对象。简单谈谈我的理解。
创建一个函数都干了些什么
1.创建一个Function类型实例
2.初始化参数,包括函数的名字,参数的个数,外层空间的引用,和一些其他配置
运行一个函数都干了些什么
1.首先创建一个自己的封闭空间
2.创建arguments对象
3.初始化变量,包括传入进来的参数,这是会出现变量提升,同名变量将进行覆盖
4.运行js代码
var a = 'a';
function b(){
a = 'b';
}
b();
console.log(a);
这段代码输出“b”。当运行代码中碰到一个变量时,他会先在自己的封闭空间中查找,如果找不到会到外层空间去找同名的变量。
var a = 'a';
function b(){
a = 'b';
return;
function a(){}
}
b();
console.log(a);
观察上面这段代码,这段代码的输出为“a”,不是“b”,发生这个原因是因为变量提升。正常情况下在函数内部找不到对应得变量,会到函数的外部引用找到同名的变量,所以这个变量就变成了外部的变量a,修改的也是这个变量。但是函数在return后声明了一个同名的a函数,变量提升后,有了内部变量a,a='b'修改的是这个函数,并不是外层的变量a。综上所述全局的变量a根本没有进行修改。
而这块封闭的区间就会形成函数闭包
function a(){
var b = 'b';
return function(){
console.log(b);
}
};
var c = a();
c();
c = null;
输出为“b”,这就形成了一个闭包,外界无法通过c直接更改它的输出值。需要注意的是每次运行a,都会创建一个新的a的内部空间并且被c引用,由于js的回收机制,只要是被引用的对象都不会被回收,这样就造成内存泄漏。记得用完c之后赋个null,这样就断掉了c对空间的引用,a的运行空间就可以被回收了。
由于这个特性,就为js编程提供了一个近似状态机的概念,比如说柯里化
js中new一个对象的过程
1. 创建新对象为{}
2. 新对象的proto指向构造函数的prototype对象,构造函数中的this被指向新对象
3. 调用构造函数,设置新对象的constructor为构造函数,
4. 将初始化完毕的新对象地址,保存到等号左边的变量中
function A(){
this.name = 'a';
};
let a = new A();
A.prototype.show = function(){
console.log(this.name);
};
function B(){
this.show();
this.name = 'b';
}
B.prototype = a;
var b = new B();
b.show();
输出为“a”,“b”。这段代码实现了原始的一种原型链,这是b.proto=B.prototype=a;这段代码可以看出原型链的查找顺序,第一次调用show函数时,b没有name属性,所以到它的proto属性中进行查找,输出为“a”;第二次调用show函数时,b有了自己的name属性,不需要到proto中查找,所以输出“b”,多层链同理。这时需要注意一点,创建a时,A.prototype并没有show函数,但是在b的构造函数中却可以调用,说明每次调用属性时都会从新查找原型链。这样可以一边创建对象一边修改原型链,不必担心已经创建的对象无法调用的问题。
网友评论