Javascript原型及闭包

 

一.函数与对象的爱恨情仇

         一切皆为对象,但并不是所有的都是对象,其中undefined, number, string, boolean)属于简单的值类型,不是对象。剩下的几种情况——函数、数组、对象、null或者new一个对象,都是对象,他们都是引用类型

 

 1.对象是属性的集合(important!!!!!)

     对象里面的一切都是属性,只有属性,没有方法--方法也是一种属性,因为它的属性表示为键值对的形式。关于函数与数组对象定义属性是以其他形式定义的。

                           

                         

反正一切(引用类型)是对象,对象是属性的集合

2.对象都是函数创建的,函数也是对象,有一种鸡生蛋蛋生鸡的逻辑(别急后面会理清这种关系的)

---关于对象都是函数创建的如:

                  

以上代码的本质  

                

 Object Array 都是函数:

console.log(typeof (Object));  // function

console.log(typeof (Array));  // function

---函数也是对象,也是属性的集合

    每个函数都有一个prototype属性(这就是为什么函数是对象了,因为它里面已经事先有一个属性了,而对象又是属性的集合,逻辑是不是很对!没毛病!)指向该函数的原型对象(既然是对象,也是属性的集合!!!),只要是对象就有一个__proto__ 属性指向构造函数

3.关于对象:

      i本人理解如果用构造函数的方法创造对象,形如就是先创建一个模型,其中Fn函数里定义了很多属性,既然Fn是函数,那么Fn就有prototype属性指向该函数的原型对象。该函数的原型对象你可以自己在里面定义一些属性,该函数的原型对象里有一个constructor属性指向该构造函数。如果你要想要继承我这些属性,可以通过new关键字,new出一个新的对象。

    ii只要new出f1新对象了,那么f1对象就会继承函数里的所有属性,既然f1是对象,那么就有__proto__属性指向构造函数的原型即

                       

iii上文说过Object 和 Array 都是函数,因为要创造此类型对象要new一个出来,说明他们也是构造函数,形如function Object(){}和function Array(){}.。并且他们已经是系统创建好了。

iiii这里先讲一下new的机制为下面的原型链做下铺垫。

                             

                                 

(这里我觉得new时,不仅把构造函数的原型对象赋给创造出来的对象,而且还继承了构造函数里定义的属性)

iiiii这里还有一个逻辑问题,关于前文说的对象都是函数创建的,函数也是对象,那么函数是怎么出来的,不可能是石头里蹦出来的吧!且看如下代码:

 

4.原型及原型链就以图解形式

         每每看到这些图,我都有一种杀人的冲动,冲动是魔鬼,理解了以后才会明白很多问题:

    

       (这里解释一下构造函数,所谓构造函数就是用来new对象的函数。其实严格来说,所有的函数都可以new一个对象,但是有些函数的定义是为了new一个对象,而有些函数则不是。另外注意,构造函数的函数名第一个字母大写(规则约定)例如:Object、Array、Function等)

     function fn(){};

     var test = new fn();

  

这里new的机制就是把test.__proto__=fn.prototype,实现原型继承。要想使用一个对象的属性,首先在自身查找这个属性,如果没有找到就在原型链上查找,直到为空为止。

5.this的指向问题

   i在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了。

   ii 构造函数情况241行中的this在没有new时this指的是window,当new以后指向函数函数本身(也是对象)。

      

iii函数作为对象一个属性时

 1.如果函数作为对象的一个属性时,并且作为对象的一个属性被调用,函数中的this指向该对象。

 

2.注意,如果fn函数不作为obj的一个属性被调用,会是什么结果呢?

   

iiii特殊情况

   

Javascript没有块(这里的块指的是{})级作用域的概念,javascript除了全局作用域之外,只有函数可以创建作用域。所以这里的f()还是一个普通的函数,是在全局作用域下运行的。

二.作用域及闭包的问题

1.且看下面例题:

两句话特别重要:1.变量声明提前,但不会赋值2.函数声明优与变量声明

alert(a)

a();var a=3; function a(){

    alert(10)

}   

alert(a)

a=6;

a();  

 

------------分割线------------------

 

alert(a)

a();var a=3;var a=function(){

    alert(10)

}   

alert(a)

a=6;

a();

第一题等价于:

           

  第二题等价于:   

      

2.寻找作用域问题

          

这里x的值时,就需要到另一个作用域中取,有人说过要到父作用域中取,其实有时候这种解释会产生歧义,要到创建这个函数的那个作用域中取值——是“创建”,而不是“调用”

上面描述的只是跨一步作用域去寻找。

如果跨了一步,还没找到呢?——接着跨!——一直跨到全局作用域为止。要是在全局作用域中都没有找到,那就是真的没有了。

这个一步一步“跨”的路线,我们称之为——作用域链

我们拿文字总结一下取自由变量时的这个“作用域链”过程:(假设a是自由量)

第一步,现在当前作用域查找a,如果有则获取并结束。如果没有则继续;

第二步,如果当前作用域是全局作用域,则证明a未定义,结束;否则继续;

第三步,(不是全局作用域,那就是函数作用域)将创建该函数的作用域作为当前作用域;

第四步,跳转到第一步。

3.闭包

  只要知道应用的两个情况就可以了:

第一:函数作为返回值

          

第二:函数作为参数传递

           

这里也用到跨作用域了,在执行到11行时,寻找max在自己的作用域找不到时,就跨到全局作用域去找。

 

本文参考:http://www.cnblogs.com/wangfupeng1988/p/3977924.html

感想:本文是在2017年11月下旬面试总结下来的,个人感觉学知识,学技术,不能知其然,不知其所以然,不能抱着侥幸的心理。

 

    

原文地址:https://www.cnblogs.com/youtian/p/7859609.html