jquery - javascript设计思想
阿神
阿神 2017-04-10 16:13:53
[JavaScript讨论组]
var getSingle=function(fn){
    var result;
    return function(){
    //下面这里是实现对象是否存在,存在就返回,
    //但还是不太理解这句话fn.call(this),
    //this是window,window类似继承fn的方法?是这样吗?谁能具体说明下他的实现原理
    return result ||(result=fn.call(this));

    }
//  上面return function为何换成下面的方式却没用?
//  if(!result){
//      result=fn.call(this);
//  }
//  return result;
}
var createLoginLayer=function(){
    var p=document.createElement("p");
    p.innerHTML="我是登录浮窗";
    p.style.display="none";
    document.body.appendChild(p);
    return p;
}
var createSingleLoginLayer=getSingle(createLoginLayer);
document.getElementById("loginBtn").onclick=function(){
    var loginLayer=createSingleLoginLayer();
    loginLayer.style.display="block";
}
阿神
阿神

闭关修行中......

全部回复(3)
大家讲道理

这是一个单例模式.
在这个里面fn.call(this)其实没有什么用(大家都喜欢这么写),可以直接写成fn(),你的问题不在这里可以等有时间的话看一下call的用法。
你需要理解的是闭包,变量的作用域是词法作用域,就是说当写下一个变量名这个变量是以前定义的哪个变量,是看你写这个变量名的位置。上面的代码等价的代码是:

function getSingle(fn) 
{
  var result;
  function ret(){
        return result ||(result=fn());
  }
  return ret;
}
createSingleLoginLayer = getSingle(createLoginLayer);
//此时,这个createSingleLoginLayer函数就是上面那个 ret 函数
//当调用函数createSingleLoginLayer 的时候里面的 result 就是 getSingle 中定义的 result,这个 result会一直保存。所以只会创建一个登录框。

但是如果改成你说的方法,由于 result 是局部变量,每次调用 getSingle 都会创建一个新的 result跟前一次创建的无关。
第一种写法里,resultret都是局部变量,在每次getSingle都会创建一对新的,但是ret会被返回,保存到createSingleLoginLayer里。ret中的result 就是与他同时分配的那个result。那么调用createSingleLoginLayer就是调用ret,其中的result就是ret对应的那个result。简单来说就是 js 保存了retresult 的对应关系。
实际实现就是,对于所有变量(包括函数中的局部变量)浏览器创建这些变量之后都不会释放这些变量,这样每次函数调用都会创建一系列对应的局部变量,这一系列局部变量的组合组成一级作用域,其父级作用域就是创建的函数所在的那一级作用域。getSingle 是在全局创建的,所以其父级作用域就是全局作用域。ret是在某次执行getSingle的时候创建的,所以执行ret时候生成的作用域的父级作用域就是那次调用getSingle函数时候生成的作用域,所以引用result(本作用域没有)就是父级作用域中,也就是那次调用getSingle时候生成的result
总结一下就是,函数中的局部变量在每次调用函数的时候都会重新分配,而函数返回之后这些变量不会被释放(没有gc(注:1)),这些变量只是在不同作用域的同名变量而已(简单说就是js保存了这些变量间的对应关系),每次函数函数调用都会生成的父级作用域就是函数定义所在的那个作用域(函数执行的时候ret中的result是与ret同时分配的那个result)。

(1):对那些使用堆栈调用函数的语言来说,局部变量在函数返回之后就被释放了,其实这条不适用于 js. js会一直保存着这些局部变量,gc(垃圾回收)只是js中的一种优化而已,既然是优化我们在写代码的时候就可不考虑这个优化,认为gc是不存在的。(当然,gc的优化还是很有必要的,闭包太多的话使得gc不能释放这些局部变量最终会导致内存溢出)

天蓬老师

1)原getSingle函数的目的是返回一个函数对象
2)如return function修改成你所示的

if(!result){
    result=fn.call(this);
}
return result;

那么getSingle函数返回就是传入的函数fn的执行结果,此时就会立马创建出一个 登录浮窗 DOM对象,在click事件监听器执行就会报错并且压根就没有单例效果-result是一个局部变量,在函数执行完后就会被销毁
3)fn.call(this);以this指向的对象作为fn函数的this(上下文环境)执行fn函数
4)

var getSingle=function(fn){
    var result;
    return function(){
        return result ||(result=fn.call(this));
    }
}

以上函数执行后将返回一个函数对象,我们称之为getSingleOfFN,这个函数对象有一个闭包环境,在其执行的时候能够访问在getSingle函数中定义的变量result。
那么在getSingleOfFN函数第1次执行的后,将判断result变量是否存在,如果存在,那么或操作将被短路,直接返回;否则执行传递给getSingle函数的fn函数,将结果赋值给result并返回。
(利用闭包实现了一个变量的隐藏)

5) 下面代码供参考,简洁些

var getSingle=function(fn){
    var result;
    return function(){
        return result ||(fn&&(result=fn.call(this)));
    }
}
var createLoginLayer=getSingle(function(){
        var p=document.createElement("p");
        p.innerHTML="我是登录浮窗";
        p.style.display="none";
        document.body.appendChild(p);
        return p;
    });

直接调用执行createLoginLayer即可

迷茫

其实fn.call(this)就是一回调函数,正如楼上所说可以写成fn()

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号