05 -- 递归、预编译

小练习1:N的阶乘

//n的阶乘一般求法:
function mul(n){
    var num = 1;
    for(var i = 1;i<=n; i++){
       num *=i;
    }
    return num;
}

mul(5)
//递归:
//规律n! = n * (n - 1);
function mul(n){
    if(n == 1 ||  n==0){
        return 1;
    }
    return n * mul(n-1);
}

mul(5);

递归需要注意的两点:1.找规律、2.找出口。没有出口的话递归就会无限死循环,所以必须用一个已知的条件当做它的出口。递归只有一个好处让代码变得简洁,除此之外无任何好处。递归的速度特别慢(因为每一个结果都要等待下一次递归执行的结果), 所以特别复杂的程序不能用递归。

小练习2:菲波那切数列

//规律 fb(n) = fb(n-1) + fb(n- 2)
function fb(n){
    if(n ==1 || n ==2){
        return 1;
    }
    return fb(n) = fb(n-1) + fb(n- 2);
}

递归最典型的就是这两个:阶乘和菲波那切数列。有规律有出口就可以大胆的使用递归。


作用域初探

1、作用域定义:变量(变量作用域又称上下文)和函数生效(能被访问)的区域。

function test(){
    var a = 123;
    function demo(){
        var b = 234;
        document.write(a);
    }
    demo();
    document.write(b);
}
test();

结果:123、undefined
互相嵌套的函数,外层的函数不能访问里层的变量,但里层的函数可以访问外层的变量,也就是越往里它的权限就越大。

2、全局、局部变量
定义在全局的变量称为全局变量,定义在函数内部的变量称为局部变量。

3、作用域的访问顺序

js运行三部曲

1、语法分析
javascript的两大特点,单线程和解释性语言。js在执行的时候是解释一行执行一行而不是通篇编译再执行,但在执行之前会先通篇扫描一下有没有低级的语法错误,比如多个大括号,有中文符号等等,但不执行。这个扫描过程就叫语法分析的过程。 然后进行预编译,最后在再解释执行。

2、预编译

对于预编译,记住两句话:

  • 函数声明整体提升,也就是只要你写了一个函数声明,无论写在那里,系统都会把函数提到逻辑的最前面、所以不管在那里调用它,本质上都是在函数下面调用;
  • 变量 声明提升,变量一旦声明,无论是否赋值,变量的声明都会被提升到逻辑的最前面,但仅仅是声明被提升了,变量的赋值并不被提升。

但是这两句话解决不了所有的问题,来看一下下面这个:

console.log(a);
function a(a){
    var a = 234;
    var a = function(){  
    }
    a()
}
var a = 123;

函数名和变量名重了要怎么办呢?这就是那两句话不能解决的问题。学完预编译,所有的问题都会解决。

预编译前奏

  • 1.imply global 暗示全局变量:即任何变量,如果变量未经声明及赋值,此变量就为全局对象(window)所有。全局上的任何变量,即使声明了也归window所有。
    • eg: a = 123;
    • eg: var a = b = 123; (注意连续 赋值是自右向左的)
//window就是全局的域
var a = 123;
//相当于在window里添加
//window{
//    a:123;
//}
//如果变量定义在全局上,那就相当于在全局上挂了一个这样的属性。
//下一次在访问这个a的时候,会在windows里面去找是否有这个a。
  • 2.一切声明的全局变量,全是window的属性。

    • eg: var a = 123; ===> window.a = 123;
  • 3.window就是全局。

function fn(a){
    console.log(a);    

    var a = 123;

    console.log(a);    

    function a(){};

    console.log(a);     

    var b = function(){};

    console.log(b);     

    function d(){}
}

fn(1);

既有变量又有函数,都存在提升,也会存在一个覆盖的问题,那么这里任何提升?谁覆盖谁呢?这就是预编译发生的奇妙的过程。

预编译发生在函数执行的前一刻。预编译经过如下四个过程:

预编译四部曲

  • 1.创建AO对象:Activation Object(执行期上下文)
AO{
    //AO对象
}
  • 2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined。这里讲的是函数的,全局比较简单。
AO{
    a: undefined;
    b: undefined;
}
  • 3.将实参和形参统一
AO{
    a: 1;
    b: undefined;
}
  • 4.在函数体里面找函数声明,值赋予函数体(注意是函数声明而不是函数表达式
AO{
    a: function d(){};
    b: undefined;
    d: function d(){}
}

预编译四部曲的第四部优先级最高。到这里预编译基本完成,开始解释执行。执行期上下文相当于作用域。
3、解释执行
解释执行时,变量的值是在AO里面找的,如上面第四步所示。

function fn(a){
    console.log(a);       //function a(){}

    var a = 123;  //预编译时,变量的声明已经被提升,
    //所以这里未执行的只有a=123这个赋值语句,
    //也就是相当于重新给a赋值,覆盖了AO里面的原始的a的值,
    //到这里,a的值为123,而不是function...

    console.log(a);       //123 

    function a(){};   //解释执行时,预编译看过的地方不用再看。

    console.log(a);      //123

    var b = function(){};   //b变成function(){} ==>  b: function(){}

    console.log(b);     //function(){}

    function d(){}
}

fn(1);

所以最后的执行结果是:

function a(){}
123
123
function (){}

再看一个例子:

function test(a, b){
    document.write(a);
    c = 0;
    var c;
    a = 3;
    b = 2;
    document.write(b);
    function b(){};
    function d(){};
    document.write(b);
}
test(1);

经过预编译四部曲后的AO:

//第一、二步:
AO{
    a: undefined;
    b: undefined;
    c: undefined;
}
//第三步:
AO{
    a: 1;
    b: undefined;
    c: undefined;
}
//第四步:
AO{
    a: 1;
    b: function b(){};
    c: undefined;
    d: function(){};
}
//最后执行后的结果为:
//1
//2
//2

再举几个栗子:

function test(a, b){
    console.log(a);
    console.log(b);
    var b = 234;
    console.log(b);
    a = 123;
    console.log(a);
    function a(){};
    var a;
    b = 234;
    var b = function(){};
    console.log(a);
    console.log(b);
}
test(1)

//AO
AO{
    a: function a(){};
    b: undefined;
}

结果:

function a(){}
undefined
234
123
123
function(){}

预编译不止发生在函数里,还发生在全局。来看一下全局的预编译:

  • 1.生成一个GO 对象 Global Object。GO===window。
    其他是一样的,不过全局没有参数。
console.log(window.a) === console.log(GO.a) 
也就相当于console.log(a)
function test(){
    var a = b = 123;
    console.log(window.b);    //123
    console.log(window.a);    //undefined
}
test();

GO{
    b: 123;   //未经声明的变量归GO所有。
}

AO{
    a: undefined;
}

AO和GO,先生成GO;

最后看一个特别恶心的栗子:

GO{
    test: function(){
        //...
    }
}

console.log(test);    //   结果 ==> function test(){...}
function test(test){
    console.log(test);    // 结果 ==> function test(){//函数内部这个 }
    //这里GO和AO里面都有test,先找AO里面的值,
    //也就是遵循一个我自己有就用自己的,我没有才用别人的原则。
    var test = 234;
    console.log(test);     //234
    function test(){
    }
}

AO{
    // 先是  test: undefiend;
    test: function test(){
    },
}

test(1);
var test = 123;

再看一个:

//Go{
// a: undefiend;
// c: 234;    暗示全局变量
//}

function test(){
    console.log(b);    // undefined
    if(a){    //注意,找变量声明和形参的时候不执行if或for语句,直接把里面的东西拿出来
        var b = 100;
    }
    console.log(b);    // undefined
    c = 234;
    console.log(c);    //234
}

var a;
test();
//AO{
//    b: undefiend;
//}
a = 10;
console.log(a);    // 10
console.log(c);     //234

13年百度面试题1:

function bar(){
    return foo;
    foo = 10;
    function foo(){
    }
    var foo = 11;
}
console.log(bar());     // function foo(){}

13年百度面试题2:

console.log(bar());        //11
function bar(){
    foo = 10;
    function foo(){
       
    }
    var foo = 11;
    return foo;
}

练习1:

a = 100;
function demo(e){
    function e(){  };
    arguments[0] = 2;
    console.log(e);    //2
    if(a){
        var b = 123;
         function c(){
              //以前可以在if里面定义function,现在不允许了
         }
    }
    var c;
    a = 10;
    var a;
    console.log(b);    //undefined
    f = 123;
    console.log(c);    //function (){ }
    console.log(a);     //10
}
var a ;
demo(1);
console.log(a);   //100
console.log(f);    //123

练习2:

var str = false + 1;     
console.log(str);    // 1
var demo = false == 1;
conso.log(demo);   // false
if(typeof(a) &&-true + (+undefined) + ""){
    //  typeof(a)  ==> 字符串型的undefined
    //-true + (+undefined) + ""  ==> NaN
    console.log("基础扎实");
}
if(11 + "11" * 2 == 33){
    console.log("基础扎实);
}
!!" " + !!"" - false||console.log("你觉得能打印,你就是猪");
// 空格字符串是ture,!!就能把它变成布尔值
//空字符串是false,!!就能把它变成布尔值

typeof()是唯一一个使用未定义的变量不报错,返回undefined的方法。typeof(null)返回对象。一般数学符号的隐式转换,都是转换为number,转换不了的一般都是NaN。

练习3:css中display的属性有几种?

none    隐藏元素
block    块级元素
inline   行内元素
inline-block    

练习4:window.foo的值为?

(window.foo || (window.foo = 'bar'));
//   ||的优先级高于=
// bar(先读括号)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容

  • 1.一个功能抽象为一个函数,单独提取出来,达到复用的目的。 2.递归,先执行的最后执行完。 3.定义在全局的叫全局...
    Sune小叶子阅读 463评论 0 0
  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,145评论 0 13
  • 我数了数距离中考还有整整二十一天。氛围自开学以来便有了翻天覆地的变化。我也觉得自己变了很多。 或许发现课间是漫长的...
    萤火虫罐子阅读 196评论 0 0
  • 1.cardiac arrest The patient died after suffering a cardi...
    joketer阅读 1,215评论 2 1
  • 因为 getResources().getDrawable()已过时:
    快乐小哥阅读 1,141评论 0 1