执行环境
执行环境是什么?
- javascript的解释器每次开始执行一个函数时,都会为每个函数创建一个执行环境(execution context)。
- 执行环境定义了变量或者函数有权访问的其他数据,决定了他们各自的行为。
- 与执行环境相关的变量对象(ariable object)中有执行环境定义的所有变量和函数
作用域链
- 代码在一个环境中执行,便会创建变量对象的一个作用域链(scope chain)。
- 作用域链的作用是,保证对执行环境有权访问的所有变量和函数的有序访问
- 如果环境是函数,则其活动对象(active object)为环境变量
- 活动对象最开始含有一个变量,名为arguments对象(该变量全局中不存在)
- 作用域链的下一个对象来自包含对象,再下一个对象来自下一个包含环境...
- 标识符的解析是沿着作用域链逐级向上搜索标识符的过程
- 通过try catch/with 来延长作用域
- 没有块级作用域(类C的花括号)
代码示例
var color = "blue";
function changeColor(){
if(color == "blue"){
color = "red";
}else{
color = "blue";
}
}
changeColor();
alert(color); // red
var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColor(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
// 能访问 color和anotherColor,tempColor
}
// 能访问 color和anotherColor
swapColor();
alert(color);
alert(anotherColor);
}
// 能访问 color
changeColor();
alert(color);
alert(anotherColor); //不能被访问到 undefined
<pre><code><br />####js 垃圾回收 Garbage Collection(GC)
> - javascript具有自动垃圾回收机制
- 两种策略,标记清除和引用计数
- 标记清除(较为常见),第一遍标记所有变量,第二次标记待清除变量
- 引用计数,通过检测变量引用次数的值判定是否变量可以被回收,问题是存在循环引用问题
####Function 类型
> - 每个函数都是Function类型的实例
- 函数是对象,具有属性和方法,函数名实际上便是指向函数对象的指针
- 函数定义的三种方式
- 函数没有重载,后定义的会覆盖之前的
- 将函数名作为变量进行传参
- 函数的两个内部属性**`arguments`**和**`this`**还有一个**`caller`**
- 函数的属性(有个疑问,和内部属性什么区别么),两个`length`(参数个数)和`prototype`
- 两个非继承方法`apply()` `call()`
####代码示例
*函数的三种定义方式*
</code></pre>
// 函数定义的三种方式
// 函数声明
function sum(num1,num2){
return num1 + num2;
}
// 函数表达式
var sum = function(num1,num2){
return num1 + num2;
};
// 使用Function构造函数 两次代码解析性能慢 不推荐
var sum = new Function("num1","num2","return num1 + num2");
<pre><code>*函数声明提升(function declaration hositing)*
</code></pre>
// 可以访问sum
alert(sum(10,10));
function sum(num1,num2){
return num1 + num2;
}
// 函数表达式则不行
alert(sum1(10,10));
var sum1 = function(num1,num2){
return num1 + num2;
}
<pre><code>这是因为解析器在向执行环境加载数据时候,对于函数声明和函数表达式,解析器会率先读取函数声明,使其在任何代码之前可用(可以访问)
*作为值的函数,函数名做为变量进行传参*
</code></pre>
function callSomeFunction(someFunction,someArgument){
return someFunction(someArgument);
}
function add10(num1){
return num1 + 10;
}
var result = callSomeFunction(add10,10);
alert(result);
<pre><code><br />*函数的内部属性*
arguments对象上一篇笔记提及,类数组对象包含传入函数的所有参数
arguments对象拥有一个名为 `callee`的属性,该属性是一个指针,指向arguments对象的函数
它的作用:
</code></pre>
function factorial(num){
if(num <= 1){
return 1;
}else{
// return num * factorial(num - 1);
return num * arguments.callee(num - 1);
}
}
var trueFactorial = factorial;
factorial = function(){
return 0;
}
alert(trueFactorial(5)); // 120
alert(factorial(5)); // 0
<pre><code>`callee`作为指针的用法,解除了函数体内代码和函数名的耦合
**`this`**(很重要,要理解掌握)
this引用的是函数据以执行的环境对象或者说是this值(全局作用域调用函数时,this指向的引用就是window)
</code></pre>
window.color = "red";
var o = {
color:"blue"
};
function sayColor(){
alert(this.color);
}
sayColor();
o.sayColor = sayColor; // 函数名是指向函数的指针
o.sayColor();
<pre><code>可以通过调试代码,查看当前所在的this指向的环境对象
**疑问:如果window.color 直接写color/var color,不是应该也是指向全局的么,为什么会报undefined**
*两个非继承的方法apply() call()*
</code></pre>
// apply() call() bind()
function sum(num1,num2){
return num1 + num2;
}
function applySum(num1,num2){
return sum.apply(this,arguments); // 传入arguments
// return sum.call(this,[num1,num2]; //或者传入数组
}
alert(callSum(10,10));
function callSum(num1,num2){
return sum.call(this,num1,num2);
}
alert(callSum(10,10));
<pre><code>*apply()和call() 的作用在于 扩充函数作用域(不明觉厉)*
</code></pre>
window.color = "red";
var o = {
color:"blue"
};
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o); // bind方法 传入对象o
objectSayColor();
sayColor();
sayColor.call(this);
sayColor.call(window);
sayColor.call(o);
小结
- 执行环境的概念
- 什么是作用域,作用域链的作用
- 函数是个对象,有相应的属性和方法
- 前面的哪个疑问 是什么原因?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。