变量
- imply global 暗示全局变量:即任何变量,如果变量未经声明就赋值,此变量就位全局对象所有。
- 一切声明的全局变量,全是window的属性 window就是全局的域
预编译
- 创建AO对象 Activation Object(执行期上下文 ) (全局创建GO对象 Global Object)
- 找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
- 将实参值和形参统一
- 在函数体里面找函数声明,值赋予函数体
(if语句中不允许出现函数声明)
函数定义的方法
- 函数声明
function fn(){}
- 函数表达式
var fn = function(){}
匿名函数表达式
var fn = function test(){}
命名函数表达式
参数
- 获取实参
arguments
- 获取形参长度
函数名.length
函数的形参和arguments有映射关系但不是同一个,形参赋值,arguments里的值跟着改变,若实参为空,形参的值和arguments中对应的值没有映射关系,即使后边给arguments赋值也没有映射关系
例如:
function test(a){
console.log(arguments[0])//1
a=10;
console.log(arguments[0])//10
arguments[0]=20;
console.log(a)//20
}
test(1)
---------------------------------------------
function demo(a,b){
console.log(arguments[1])//undefined
console.log(b)//undefined
b=10;
console.log(arguments[1])//undefined
console.log(b)//10
arguments[1]=20;
console.log(arguments[1])//20
console.log(b)//10
}
demo(1)
作用域
[[scope]]
:指的就是我们所说的作用域,其中存储了执行期上下文的集合
作用域链
:[[scope]]
中所存储的执行期上下文对象的集合,这个集合呈链式链接,我们把这种链式链接叫做作用域链
function a(){
function b(){
function c(){}
c()
}
b()
}
a()
//作用域链详解
a defined a.[[scope]] -- > 0 : GO
a doing a.[[scope]] -- > 0 : aAO
1 : GO
b defined b.[[scope]] -- > 0 : aAO
1 : GO
b doing b.[[scope]] -- > 0 : bAO
1 : aAO
2 : GO
c defined c.[[scope]] -- > 0 : bAO
1 : aAO
2 : GO
c doing c.[[scope]] -- > 0 : cAO
1 : bAO
2 : aAO
3 : GO
闭包
当内部函数被保存到外部时,将会生成闭包。闭包会导致原有作用域链不释放,造成内存泄漏。
闭包的作用
- 实现公有变量 eg:实现一个累加器
function add(){
var count = 0;
function b(){
count++;
console.log(count)
}
return b;
}
var Counter = add();
Counter()
Counter()
Counter()
Counter()
- 可以做缓存 (存储结构)
function eater(){
var food = "";
var obj = {
eat : function () {
console.log("i am eating " + food);
food = "";
},
push : function (myFood) {
food = myFood;
}
}
return obj;
}
var eater1 = eater();
eater1.push('banana');
eater1.eat();//i am eating banana
- 可以实现封装,属性私有化
function Zhang(name,wife){
var prepareWife = 'xiaozhang';
this.name = name;
this.wife = wife;
this.divorce = function(target){
this.wife = prepareWife;
}
this.changePrepareWife = function (target){
prepareWife = target;
}
this.sayPraprewife = function () {
console.log(prepareWife);
}
}
var zhang = new Zhang('zhang','xiaoliu');
//只有自己能看到或者设置了向外展示的方法
console.log(zhang.prepareWife) //undefined
console.log(zhang.sayPraprewife())//xiaozhang
- 模块化开发,防止污染全局变量
var name = 'abc';
var init = (function () {
var name = 'aaa';
function callName() {
console.log(name)
}
return function (){
callName();
}
}())
console.log(init())//aaa
立即执行函数 - 针对初始化功能的函数
此类函数没有声明,在一次执行过后即释放,适合做初始化工作
只有表达式才能被执行符号执行
function test(a,b,c,d){
console.log(a,b,c,d);
}(1,2,3,4)
//被解析成↓↓↓两部分(能不报错就不报错原则)
function test(a,b,c,d){
console.log(a,b,c,d)
}
(1,2,3,4)
//不报错
call 和 apply、bind
- 作用:改变this指向
- 区别:传参列表不同
- call 需要把实参按照形参的个数传进去
- apply 需要传一个arguments(数组形式的实参列表)
- bind 传参和call一致,返回一个函数需再次执行
//Person() => Person.call() 两者等价
//Person([1,2,3]) => Person.apply(null,[1,2,3]) 等价
//Person.call(obj,xxx,xxx)
//Person.bind(obj,xxx,xxx)()
//第一个参数:this指的方向
//第二、三...个参数:传进Person的实参、
function Person(name,age){
this.name = name;
this.age = age;
}
var person = new Person('deng',100);
//1.
var obj = {};
Person.call(obj, 'cheng', 300)
console.log(obj)//{name:'cheng',age:300}
//2.
function Student(name,age,sex,tel,grade){
Person.call(this,name,age);
this.sex=sex;
this.tel=tel;
this.grade=grade;
}
var student = new Student("sunny",123,'male',152,2017)
arguments.callee
//arguments.callee指向函数引用(函数自身)
var num = (function(n){
if(n==1){
return 1;
}
return n*arguments.callee(n-1)
}(10))
caller
//调用该函数的环境
function test(){
demo()
}
function demo(){
console.log(demo.caller)// test函数
}
test()