J29 函数在浏览器中执行的机制

163 阅读5分钟

函数执行

1.函数

1.表达式方式创建函数,在变量提升阶段,并不会给函数赋值,这样只有代码执行的过程中,函数赋值后才可以执行(不能在赋值之前执行)

  • 符合严谨的执行逻辑

  • 真实项目中推荐的方式

    //1.不推荐使用 func();//=>ok function func() { console.log('OK'); }

    //2. var func = function () { console.log('OK'); }; func();分析步骤: 1.变量提升:var func; (默认值是undefined) 2. func(); 执行 3.相当于 undefined() =>Uncaught TypeError: func is not a function 报错一下代码不在执行

2.匿名函数

为了保证语法的规范性,JS中原本创建的匿名函数,我们最好设置一个名字,但是这个名字在函数外面还是无法使用的,只能在本函数体中使用(一般也不用)

//1.函数内没有return,所以不能暴露给函数外使用,报错后 ,下面代码不在执行

var func = function anonymous() {
	// console.log(anonymous); //=>当前这个函数本身
};
// console.log(anonymous); 
//=>Uncaught ReferenceError: anonymous is not defined 函数内没有return所以函数不能使用
func();

//2.
var func = function func() {
	console.log(func); //=>函数名func本身
};
console.log(func); //=>变量func,存储的值是函数
func();
3.条件判断中包含函数执行

在当前执行上下文中,不管条件是否成立,变量提升是有效的

/*
 * 全局上下文中的变量提升:
 *    [VO(G) 全局变量对象]
 *    var n;  不论IF条件是否成立
 */

console.log(n); //=>undefined
if (1 > 1) { //=>条件不成立
	var n = 100;
}
console.log(n); //=>undefined

/*
* 全局上下文中的变量提升:
*   [VO(G) 全局变量对象]
*    [IE 10及以前以及谷歌等浏览器低版本状态下]
*  function func(){ ... }  声明+定义都处理了
* 
* [最新版本的浏览器中,机制变了]
*  function func;  //=>用判断或者循环等包裹起来的函数,在变量提升阶段,不论条件是否成立,
此处只会先声明
*/

console.log(func); //=>undefined
if (1 === 1) {//=>1.此时条件成立,进来的第一件事情还是先把函数定义了(迎合ES6中的块作用域)
              //=>2.func=function(){ .... }
    console.log(func); //=>函数本身
    function func() {
    console.log('OK');
}
console.log(func); //=>函数本身
}
console.log(func); //=>函数本身
4.检测对象中是否包含某个属性名
  • 第一种检测方式

    var obj = { name: 'Hello' };

    要求:验证:name或者age是不是obj的属性

    // 1.基于判断属性值是否为undefined来验证是否有这个属性 if (obj.name !== undefined) { // OBJ中存在这个属性 } if (obj['age'] === undefined) { // OBJ不存在这个属性 }

    // 2.基于检测符 in 来检测当前属性是否属于这个对象 =>语法: 属性名 in 对象

    if ('age' in obj) { // AGE是OBJ属性返回TRUE,不是它的属性返回FALSE }

5.案例
/*
 * 全局上下文中的变量提升
 *     var a;
 *       ->给VO(G)中新增一个全局变量 a
 *       ->给GO中新增一个属性 a
 *       ->默认值都是 undefined
 */

console.log(a); //=>undefined
if (!('a' in window)) {
// 'a' in window 检测a是否为window的一个属性 =>TRUE
// !true => FALSE  条件不成立
	var a = 13;
}
console.log(a); //=>undefined

/*分析:
 * 全局上下文中的变量提升(最新版本浏览器中)
 *     function fn;
 *       ->VO(G)中存在一个fn全局变量
 *       ->GO中存在一个fn属性
 */

console.log(fn); //=>undefined

 fn();//=> undefined() =>Uncaught TypeError: fn is not a function 
 //=>JS中,一但当前代码报错,那么下面的代码都不会再执行了

if ('fn' in window) {
	fn(); 
	function fn() {
		console.log('哈哈哈');
	}
}
fn();

/*分析:
 * 全局上下文中的变量提升(最新版本浏览器中)
 *     function fn;
 *       ->VO(G)中存在一个fn全局变量
 *       ->GO中存在一个fn属性
 */

console.log(fn); //=>undefined

if ('fn' in window) {  //=>TRUE
//=> 进来第一件事情:给FN赋值  fn=function(){ ... }

fn(); //=>'哈哈哈'

function fn() {
	console.log('哈哈哈');
	}
}
fn(); //=>'哈哈哈'

//分析:
// 分析:浏览器有一个特征:做过的事情不会重新再做第二遍(例如:不会重复声明)
/*
 * 全局上下文中的变量提升
 *     fn = function(){ 1 }  声明+定义
 *        = function(){ 2 }
 *     var fn; 声明这一步不处理了(已经声明过了)
 *        = function(){ 4 }
 *        = function(){ 5 }
 * 结果:声明一个全局变量fn,赋的值是 function(){ 5 }
 */

fn(); //=>5
function fn(){ console.log(1); }  //=>跳过(变量提升的时候搞过了)
fn(); //=>5
function fn(){ console.log(2); }  //=>跳过
fn(); //=>5
var fn = function(){ console.log(3); }
//=>var fn; 这一步跳过,但是赋值这个操作在变量提升阶段没有搞过,需要执行一次  => fn = function(){ 3 }
fn(); //=>3
function fn(){ console.log(4); } 
//=>跳过
fn(); //=>3
function fn(){ console.log(5); } 
//=>跳过
fn(); //=>3

/*
 * 高版本浏览器 
 * 全局上下文中变量提升:没有
 */

f=function (){return true;};//=>给GO中设置一个属性 f = function () {return true;}
g=function (){return false;};//=>给GO中设置一个属性 g = function () {return false;}
(function () {
/* 
 * 自执行函数执行,形成一个私有的执行上下文
 *    [变量提升]
 *    function g;
 *    高版本浏览器中,在判断和循环中的函数,变量提升阶段只声明不定义
 *
 * 条件解析:
 *  g() ;
 *  undefined() => Uncaught TypeError: g is not a function
 * 下面操作都不在执行了
 */
    if (g() && [] == ![]) {
        f = function () {return false;} 
        function g() {return true;}
    }
})();
console.log(f());//=>false
console.log(g());//=>false

/*分析:
 * 低版本浏览器(包含IE10及以内) 
 * 全局上下文中变量提升
 *    没有
 */

f=function (){return true;};
//给GO中设置一个属性 f = function () {return true;}

g=function (){return false;};
//给GO中设置一个属性 g = function () {return false;}

(function () {
	/* 
	 * 自执行函数执行,形成一个私有的执行上下文
	 *    [变量提升]
	 *    function g(){return true;}
	 */
	// 条件解析:
	// g(); //=> 私有的G执行 TRUE
	// []==![] => []==false => 0==0 => TRUE

    if (g() && [] == ![]) { //=>条件成立

f = function () {return false;}
//f不是自己私有的,则向上查找,属于全局对象中的f,
//=>此处是把全局对象中的 f = function () {return false;}

function g() {return true;}
//跳过(变量提升处理过了)
}
})();
console.log(f()); //=>FALSE
console.log(g()); //=>FALSE  这个G找全局的(函数里面的G是自己私有的)