码迷,mamicode.com
首页 > 其他好文 > 详细

作用域链、闭包和原型链

时间:2016-10-16 13:58:42      阅读:484      评论:0      收藏:0      [点我收藏+]

标签:

Function:  匿名函数,作用域,作用域链和闭包

函数的重载:  什么是:函数名相同,参数列表不同.根据传入函数的参数的不同,整形不同的逻辑.  

何时用:如果一项任务,根据不同的参数,不执行不用的逻辑.  

优点:减轻调用者的负担.  问题:js语法不知函数的重载.

 解决办法:在函数中都有arguments的属性,专门用于接收传入函数的所有参数值的类数组对象.

匿名函数:  什么是:在函数定义时,不给函数名,即不被任何变量引用.  

何时用:确定函数只使用一次.  优点:节约内存.  

如何用:1.自调()--定义完立即执行.;2回调()--定以后,传给其他函数使用;

作用域:  什么是:变量的有效范围.

 函数的生命周期(四个部分):

   1.程序开始执行    执行环境栈-Execution Context Stack:专门按顺序保存每个函数的执行环境的集合.    全局EC:开始执行程序时,首先将全局EC压入ECS中.    创建window对象,保存所有全局函数和变量.window其实就是全局作用域.  

  2.函数声明时    创建函数对象,封装函数定义.    用函数名创建一个变量,引用函数对象.    在函数中添加scope属性,用来引用函数来自的作用域对象.

  3.函数调用时    创建活动对象:Active Object.专门用来保存调用函数时的中局部变量.    AO其实就是函数作用域对象;    AO中的parent属性会引用函数来自的父级作用域对象.由此便形成了作用域链.    作用域链控制着变量的使用顺序,局部优先,然后是全局变量.    在再ECS中压入函数的执行环境.并且有属性scope chain 引用了AO

  4.函数调用后    函数的执行环境弹栈,则AO伴随着引用消失而消失,则局部变量也跟着消失. 闭包  什么是:能保证局部变量的重用,又能保护其不受污染.

 何时用:希望一个变量.......  

怎么用:3步   

  1.使用外层函数将局部变量和内层函数包裹起来.   2.外层函数将内层函数对象返回.   3.调用外层函数获得返回的内层函数对象.  笔试时,一般先找出受保护的局部变量并计算出其最后的值.然后找到引用这个变量的函数.要注意函数只有被调用时,才会执行.

判断是否是自有属性:obj.hasOwnProperty("属性名");

回顾:面向对象  三大特点:  

  封装:将一个事物的属性和功能集中定义在一个对象中.  

  继承:父对象的成员,子对象无需创建,就可使用;   即重用了代码,又节省了内存.

   多态-重写:同一种方法在不同的情况下表现出不同的状态.

  1.创建对象--封装(3种方法--前两种用于创建单独的对象)  var obj={属性名:属性值,...,方法名:function(){}};  var obj={};(new和()都能省略,但不能同时省略)obj[属性名]="属性值";  定义构造函数;var obj=new 构造函数(属性值,...);

   js底层,一切对象都是hash数组. 访问自己的属性:this.属性名;  

  new做了4件事   

   1.创建了一个空的对象;  

   2.设置新对象的_porto_属性继承构造函数的原型对象.

   3.用新对象调用构造函数对象,将构造函数的this临时替换成新对象.

   4.将生成的新对象的地址返回给变量. 2.调用对象的方法,操作对象的属性  

原型对象:prototype  是集中保存父级对象的共有成员的对象.  

  如何获得:构造函数.prototype   子对象._proto_;   其中,子对象的_proto_属性是内部属性,无法直接获得.   Object.getPrototypeOf(obj);   获取obj对象的父级原型对象. 判断自有属性和共有属性:  自有属性是指保存在子对象本地的成员,保存在父级原型对象中的是共有属性.  obj.hasOwnPrototype("属性名");    

  判断obj是否包含自有属性.(false并不能表示这个属性就是共有属性,还可能是没有)  共有属性:在之前的基础上,obj.属性名!=undefined;此时表示为共有属性. 内置对象的API浏览器兼容性问题:  内置对象的API都存储在其原型对象中,如果不支持该方法就可以直接在其原型对象中添加该方法即可,重要的是该方法的实现原理. 判断继承关系:  根据原型对象判断:  father.isPrototypeOf(child);  判断father是否是child的父级对象,同时也表示child是否是father的子对象.  根据构造函数判断:  child instancof 构造函数  判断child是否是构造函数创造出来的对象.

  笔试题:判断一个对象是否是数组类型,有几种方法.(4种)

  1.Array.prototype.isPrototypeOf(xxx);//根据原型判断  

  2.xxx instanceof Array;//根据构造函数判断  

  3.根据对象的class属性判断.   其中,只有Object的直接子类对象可以直接调用xxx.toString();方法来获取class的值.其他的子类对象的toString()方法都被重写了.如何解决呢?--call     

call强行调用函数,并且临时替换为this对象.(强行借用一个本无法调用到的函数.)  Object.prototype.toString.call(obj)--返回"[object Array]"  所以在判断一个对象是否为数组时,  判断Object.prototype.toString.call(obj)==="[object Array]"     

   4.ES5以后支持Array.isArray(obj);--其底层所示用的原理还是使用的第三种方法. 作用域链和原型链:  作用域链是js默认执行的路线,同时也是控制变量的执行顺序.  而原型链则是控制js中对象的属性的执行循序.

面向对象中多个类型间如果有相同结构的属性和方法,则需要抽象到父类型中. 例如:都有name属性和fly方法.那么就可以抽象到父类中. 那么此时,在子类对象的创建过程中遇见问题.  首先是子类对象在创建时怎么调用父类的构造方法?(这里使有call和apply方法,作用都是强行调用一个函数.并将this改为当前正在创建的新对象.不同的是,call需要单独将参数写出,而apply只用使用arguments就可以,注意参数的前后顺序.)  然后是子类对象怎么获得父类对象的的方法?继承.通过方法   Object.setPrototypeOf(子类对象.prototype,父类对象.prototype);

修改继承:  修改继承只有3种方法

   1.修改一个对象的父对象.--就是改变__proto__属性  child.__proto__=father=>Object.setPrototypeOf(child,father);  

  2.批量修改所有子对象的父对象--就是修改构造函数的prototype.  构造函数.prototype=father(强调必须在开始创建对象前修改)  

  3.两种类型间的继承       如果多个对象,拥有相同的属性结构和功能,那么就可以抽象出一个公共的父对象中  

  怎么做:  3.1 定义公共父类型,来集中定义共有的属性和功能.  

      3.2 让子类的原型对象继承父类的原型对象(目的是让子类可以使用父类中的共有方法)--inherits(继承):直接使用父对象中的成员--必须继承才能使用公共方法.    Object.setPrototypeOf(子类型构造函数.prototype,父类型构造函数.prototype);

      3.3 在子类构造函数中借用父类型构造函数--(extends)扩展:为子对象扩展父类没有的属性.  父类型构造函数.call(this,属性参数);  父类型构造函数.apply(this,arguments);  call与apply的区别--同:都是强行调用一个函数,将this改为当前正在调用的对象      异:call每个参数必须独立传入,apply所有参数放在一个集合中集中传入(argument)

ES5新特性:  对象的属性:两大类-命名属性和内部属性(不可直接修改)  

  命名属性(自定义属性):  数据属性:实际存储属性值的属性(就是通常我们所写的.)   四大特性:   value,wirtable,enumerable,configurable.(默认值都为true)   如何产看四大特性:   Object.getOwnpropertyDescriptor(obj,"属性名")   如何设置四大特性:   Object.defineProperty(obj,属性名,{//一次修改一个     特性:值,...    });   Object.defineProperties(obj,{//一次修改多个.    属性名:{     特性:值,...    }   })  访问器属性(为了保护属性-通常需要定义的):--为了自定义保护的逻辑.   四大特性:   get:function(){    return 受保护的属性值;   }   set:function(val){    //验证通过    受保护属性值=val;   }   enumerable,configurable.  何时使用:对一个属性自定义保护逻辑时.  如何使用:Object.defineProperty(   obj,"属性名",{    get:function(){return 属性值},//js自动调用    set:function(val){//验证 赋值}//js自动调用   }  ) 笔试题:在js中定义一个类型,包含共有属性和私有属性.  js中的私有属性其实就是一个受闭包保护的一个局部变量.(注意,二者必须相互配合使用才能形成私有属性) ***注意:为一个已定义好的对象添加私有属性,使用添加外层函数的闭包结构(匿名函数的自调)  为多个子类对象添加相同的私有属性.则对构造函数设置一个受闭包保护的一个局部变量.(其中,构造函数就一个外部函数,所以不用再定义.)

防篡改:防止对已经创建好的对象的属性进行增减. 三个级别:  

  1.防扩展:禁止向对象中添加新属性\  每个对象中都有一个extensible属性,控制能否向变量中添加新属性,默认为true.  Object.preventExtension(obj);//设置对象中的extensible属性为false  问题,不妨删除.      

  2.密封:即防扩展,又防删除(是通过设置每个属性的configurable为false实现的).  Object.seal(obj);  

  3.冻结:所有属性禁止增减,同时也禁止修改.  

    Object.freeze(obj); Object.create():  何时:通过一个(父)对象创建一个子对象时使用.  笔试题:写一个函数,模拟create方法的实现过程  

     3步:1.基于现有父对象创建一个新的子对象;      

    2.继承父对象      

    3.同时扩展子对象的自有属性.   --用Object,defineProperties(obj,    属性:{}   );

      注意: 原型方法/实例方法: 必须用具体对象才能调用  构造函数方法: 不需要任何具体对象即可直接调用       

ES5-数组API  判断数组中所有元素,是否符合要求:  every:判断每个元素是否都符合要求.  arr.every(function(val,idx,arr){   //回调函数用于检测每个函数   //val;自动获得当前元素值   //idx:自动获得当前元素的位置   //arr:自动获得当前正在遍历的数组  })  some:判断是否包含满足要求的元素.  遍历:  forEach:对原数组中的每个元素执行相同的操作.  arr.forEach(function(val,idx,arr){   //对arr[idx]的值做出修改  })  map:将原数组中的每个元素加工后,生成新数组.  arr.map(function(...){   //根据条件   return 新值;  })  过滤和汇总  filter:复制出原数组中符合要求的元素,组成新元素.  var newarr=arr.filter(function(...){...})  reduce:将数组中每个元素的值汇总出一个结果.

 bind:基于现有函数,创建一个新函数,提前永久绑定函数中的this为指定对象.  

笔试题----模拟实现bind方法    call与apply与bind:  call,apply:强行借用一个函数,并临时替换函数中的this为指定对象.  call与apply是执行一个函数.  bind:创建一个新函数,并永久绑定this和部分属性.  bind不是执行函数,而是创建一个函数

 

将类数组对象转为纯数组:  var new=[](或者Array.prototype).slice.call(arguments);

需要手写的函数:forEach,map,create,bind(请看下面的链接)

http://www.cnblogs.com/tianzun-blog/p/5966401.html

作用域链、闭包和原型链

标签:

原文地址:http://www.cnblogs.com/tianzun-blog/p/5966428.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!