5js面向对象基础-闭包的概念及应用
2016-11-03 00:32
387 查看
5 js面向对象基础 - 闭包的概念及应用
闭包的概念
注意:预解析,变量声明,词法作用域,作用域链等知识的理解,对闭包的彻底理解起重要的作用。没有基础的建议先看上一篇 4 js面向对象基础 - 预解析,词法作用域,作用域链字面意义:
闭 : 关闭,封闭
包 : 包裹, 打包
闭包的含义就是一个被包裹的隔离的空间
在 js 中, 什么是闭包 ?
在 js 中函数是一个具有变量作用域隔离特性的一个内存结构, 函数的内部内容外部无法访问,是一个被封闭的内容,即为一个闭包。
学习闭包, 在 js 中到底要解决什么问题
在 js 中闭包要解决的问题就是间接的访问到这个被隔离的数据.function foo () { var num = 123; return num; // return 只是进行了 拷贝,外界还是没有真正的访问 num } var num = foo();
在外界想访问到 num 中的数据. 怎么做? =》 我们可以使用闭包的间接访问
闭包的间接访问
使用 return 数据不能直接访问原来的数据, 那么可以考虑利用函数的返回访问原始数据function foo() { var num = Math.random(); // 建随机数 function fuc() { return num; /* 原始数据 num */ } return fuc; // 把函数返回 } var fn = foo(); // 获取函数引用, 返回的函数功能是 获取 foo函数中 变量 num var num1 = fn(); console.log( num1 ); // 0.4612285847198856 var num2 = fn(); console.log( num2 ); // 0.4612285847198856
fn 中存储的是 foo 里面定义的函数的 引用,可以使用 fn 来调用,根据词法作用域,返回了 foo 中的 num,间接的访问了闭包中的数据
闭包的应用
闭包的应用-利用闭包实现私有数据
function foo(){ var num1 = 123, num2 = 456; return { get_num1: function() { return num1; }, set_num1: function( value ) { num1 = value; }, get_num2: function() { return num2; } }; } var o = foo(); console.log( o.get_num1() ); // 获取 num1 123 o.set_num1(789); // 修改 num1 console.log( o.get_num1() ); // 再次获取 num1 789 console.log( o.get_num2() ); // 获取 num2 456
从上可以看到外部对 num1 可读可写,对 num2 可读不可写
函数允许返回一个对象, 那么该对象可以提供数据访问方法,但是数据存储在闭包中, 来达到私有的目的
function createPerson ( name, age, gender ) { var hasChangeGender = false; return { get_Name: function () { return name; }, set_Name: function ( value ) { name = value; }, get_Age: function () { return age; }, get_Gender: function () { return gender; }, set_Gender: function ( value ) { if ( hasChangeGender == false ) { gender = value; hasChangeGender = true; } else { throw new Error( '已经改变过一次性别了, 不能再修改了' ); } } }; } var p1 = createPerson( '张三', 19, '男' ); console.log( 'p1.name = ' + p1.get_Name() ); // 张三 console.log( 'p1.age = ' + p1.get_Age() ); // 19 console.log( 'p1.gender = ' + p1.get_Gender() ); // 男 p1.set_Name( '王二' ); p1.set_Gender( '女' ); console.log( 'p1.name = ' + p1.get_Name() ); // 王二 console.log( 'p1.age = ' + p1.get_Age() ); // 19 console.log( 'p1.gender = ' + p1.get_Gender() ); // 女 p1.set_Name( '王三' ); p1.set_Gender( '男' ); // Uncaught Error: 已经改变过一次性别了, 不能再修改了
总结:闭包实现各种特性, 其根本的核心内容只有两个
带有私有数据的 函数
function foo () { var num = 123; return function () { // 可以访问 num } } var func = foo(); // 称 func 是一个 带有私有数据的 函数 // 称 func 带有缓存
**称 func 是一个 带有私有数据的 函数** **称 func 带有缓存**
带有私有数据的 对象
闭包的应用-沙箱模式
沙箱就是一个隔离的执行环境。js 中沙箱就是一个自调用函数,写在这个函数中变量,不会被外面的内容所影响,这样的话,使得我们的数据更加的安全,代码也能正常使用和运行。在 js 中 什么情况需要使用沙箱?
function Person() {....} var p = Person. ... Person.prototype = ... ...
定义变量越多, 会怎样? -> 出现冲突的可能性越大
而有时代码中 为了使得代码更加简洁, 会引入很多变量, 我们通过沙箱就可以解决这样的问题。
(function () { // 沙箱模式 // 所有的代码写在这里 })();
闭包的应用-模拟onload事件的追加和移除
onload 事件的追加 addEvent/* 新建 jepson 对象来接收 沙箱返回的对象 */ var jepson = ( function() { /* 新建 私有变量 */ var arr = []; /* window onload 以后,遍历执行 arr数组中的全部方法 */ window.onload = function() { for( var i = 0; i < arr.length; i++ ) { if( typeof arr[ i ] == "function" ) arr[ i ](); } }; /* 返回对象,对象中存放 addEvent方法,用以追加 onload执行事件 */ return { addEvent: function( fn ) { arr.push( fn ); } } })(); jepson.addEvent( function() { console.log( " 我被追加载 onload 执行了 1 " ); });
onload 事件的移除 removeEvent
/* 新建 jepson 对象来接收 沙箱返回的对象 */ var jepson = ( function() { /* 新建 私有变量 */ var arr = []; window.onload = function() { for( var i = 0; i < arr.length; i++ ) { if( typeof arr[ i ] == "function" ) arr[ i ](); } }; return { addEvent: function( fn ) { /* 追加 */ arr.push( fn ); }, removeEvent: function( fn ) { /* 移除 */ // 遍历 arr, 发现相同的就删除 for( var i = 0; i < arr.length; i++ ) { if ( fn == arr[ i ] ) arr.splice( i, 1 ) } } } })(); /* 要删除必须传引用,所以用变量存一下引用 */ var f1 = function() { console.log( " 我被追加载 onload 执行了 1 " ); }; var f2 = function() { console.log( " 我被追加载 onload 执行了 2 " ); }; var f3 = function() { console.log( " 我被追加载 onload 执行了 3 " ); }; jepson.addEvent( f1 ); jepson.addEvent( f2 ); jepson.addEvent( f3 ); jepson.removeEvent( f1 ); // f1 被移除了
这里只会输出,f1已被移除
我被追加载 onload 执行了 2
我被追加载 onload 执行了 3
补充: setInterval函数调用时,也尽量用变量保存引用,不然每隔一秒,都会新建一个不同的函数来调用,大大的占用了内存,消耗了性能。
var f1 = function() { ... }; setInterval( f1, 1000 );
闭包的应用-模拟一个缓存结构
cache 对象, 可以使用 cache[ key ] = value 存储数据, cache[ key ] 获得数据当 cache 里面的数据达到 1024 条, 将最早放进去的数据移除。
而模拟时, cache = {} 可以存取数据, 但是不能限定数据的长度
我们需要限定数据,就是在加入数据的时候判断,是否已经超过尺寸,来决定是否移除
可以将 cache 做成函数,那么添加数据时,使用 cache( key, value ),而且函数本身也是对象
function cache ( key, value ) { // 可以在这里加上限定长度的代码 cache[ key ] = value; } cache( 'attr', function ( node, attr ) { return node.getAttribute( 'name' ) == attr; } ); cache( '__name__', '张三' );
由于需要记录键的数量. 并且需要记录添加数据的先后顺序. 所有首先考虑有序的数组.因此需要让 cache 函数带有缓存功能
搭建结构
var cache = (function () { var data = []; // 新建 data数组,用来保存 键 function cache ( key, value ) { // 准备做判断, 如果超出范围, 则, 将最开始加入的 移除 cache[ key ] = value; } return cache; })(); cache( 'age', 20 ); // 给 cache 添加 age 属性,值为 20
实现
var cache = (function () { var data = [], max = 3; function cache ( key, value ) { // 做判断, 如果超出范围, 则, 将最开始加入的 移除 if ( data.length >= 3 ) { // 需要先移除 var temp = data.shift(); // 移除第一项并获取 key delete cache[ temp ]; // 删除 cache对象中的 temp 属性 } data.push( key ); console.log( data ); cache[ key ] = value; } return cache; })(); cache( 'name1', '张三' ); cache( 'name2', '李四' ); cache( 'name3', '王五' ); cache( 'name4', '找钱' );
相关文章推荐
- php面向对象基础概念(对象和类)
- 这些基础却重要的面向对象概念,你还记得多少
- 面向对象基础——引用传递及其应用以及this关键字的使用
- 设计模式 可复用面向对象软件的基础(概念你认识多少)
- PHP面向对象基础概念(抽象方法和抽象类)
- 黑马程序员——Java基础:面向对象一些概念的区分(二)
- 黑马程序员——Java语言基础——03.面向对象(1)思想和一些概念
- 【java开发】面向对象初步认识与基础概念讲解
- 转[]面向对象基础(概念、特征、要素)
- java笔记--Day07--面向对象基础(相关概念)
- 巩固JAVA面向对象基础应用 -- 实现小巧的数据库1
- Java面向对象基础---名词概念的理解:方法的重载、构造函数、封装性
- C++学习4-面向对象编程基础(面向对象概念,定义类,定义对象)
- JAVA面向对象编程基础复习(一)面向对象基本概念
- php面向对象基础概念(封装)
- 这些基础却重要的面向对象概念,你还记得多少
- JAVA_SE基础——22.面向对象的概念
- Java基础——对象和类1(面向对象基本概念)
- [黑马IOS自学第十篇]OC语言基础,面向对象概念,类学习
- c++基础学习6-c++面向对象基本概念