用了多年javascript,用过的插件数不胜数,很多插件用起来方便易用,那么怎样开发自己的高大上插件呢,看插件的源码有一些语法觉得很高深莫测吗?谨以此文解开javascript插件开发的神秘面纱。
开发插件首先要深刻理解变量、作用域、函数和闭包。
js中一切都可以当成变量。方法也可以是变量,这点很重要。废话少说看例子
<html>
<head>
<script type=”text/javascript”>
function parent(p){
function children(c){
return p + c;
}
return children;
}
var T= parent(10);
var result = T(20);
console.log(result);//输出结果 30
</script>
</head>
<body>
</body>
</html>
这是一个神奇的例子,所蕴含的知识点贯穿全文。
方法也是变量在哪体现呢?var obj = parent(1); 这句话,方法parent的返回值 return children 返回的就是方法,obj变量就是一个方法,这样result = T(20) 就很好理解了,children(20) 输出结果10+10=30
接下来简单看看作用域:
什么是作用域,域听起来很高深的一个字,其实就是变量的作用范围,js中通常有两种情况:全局变量
和 局部变量
定义在函数内部的变量是局部变量,定义在函数外部的变量是全局变量。那么怎么理解函数内的作用范围呢?继续看这个神奇的例子:
var v = “我是全局变量”
function parent(p){
var vp = “我是父局部变量”
console.log( v) //我是全局变量
console.log( vp) //我是父局部变量
console.log( vc) //vc is not defined
function children(c){
var vc = “我是子局部变量”
console.log( v) //我是全局变量
console.log( vp) //我是父局部变量
console.log( vc) //我是子局部变量
return p + c;
}
return children;
}
console.log( v) //我是全局变量
console.log( vp) //vc is not defined
console.log( vc) //vc is not defined
注释就是输出结果,这样就清晰地知道局部变量的作用范围了吧。这就是域。
补充一个注意事项:(如果再函数内声明变量时候不用var,变量为全局变量!很重要很奇怪。比如:var vp = “我是父局部变量”改成 –>vp = “我是父局部变量”,那么vp就是全局变量,作用域和v一模一样!)
明白了作用域,我们换个角度看这个万能例子,父函数嵌套子函数,子函数能访问父函数声明的变量(也能访问父函数传递进来的参数变量),父函数不能访问子函数声明的变量,换句话说:子函数形成了一个相对独立的环境(空间)使得它自身的变量只能由它自己来访问,这里嵌套子函数就形成了一个闭包。闭包的特点是啥:父函数能调用子函数,但是不能访问子函数的局部变量,子函数能访问父函数声明的变量,类似java的继承。总结一点:函数不就是闭包嘛。
闭包的应用场景:
关于闭包在开发中的使用,最多的体现还是在 Javascript 插件的开发上面。使用闭包可以避免变量污染。也就是说你在闭包中使用的变量名称不会影响到其他地方同样名称,换个角度来讲,我将我嵌套函数内部的变量给保护起来了,外部没办法随便修改我内部定义的变量了。再看万能小例子:
function parent(){
function children(p){
var c = 10
return p + c;
}
return children;
}
var c = 100 //全局变量c=100
var result =parent()(c); //注意这里的调用很有意思
console.log(c);//输出结果 100 外部变量
console.log(result);//输出结果110,内部变量c+外部传递的100=110
虽然全局变量也叫c但是闭包保护了内部变量c=10,传进来的变量没有改变闭包内的变量值,设想,如果去掉子函数中的
var c = 10 变量声明会发生什么?结果是什么?
好了,编写插件准备完毕,接下来先从HelloWorld走入插件世界。
//声明插件 var plugin =(function(){ function _helloworld(str){ console.log(str); }; return{ helloworld: _helloworld, }; })(); //使用插件 plugin('HelloWorld!') //输出我们久违的‘HelloWorld!’
接下来一步步分析代码: (function{ //code })(); 这叫做:自调用匿名函数 -----这不就是闭包嘛。 作用:防止插件用户定义函数与插件冲突---这不就是闭包的作用嘛。 等价于: var func = function(){ //code } func(); 最后面的小括号等价func()执行函数 再看这里: return{ helloworld: _helloworld, }; 这里是类似java中一个接口声明了很多方法,我提供了plugin的接口,接口中有各种各样的方法如:helloworld 再来稍微修改下神奇的小例子更深入的理解接口和方法(为了更清晰地解释本人对比java的概念,不要混淆)
//声明插件 var plugin =(function(){ function _helloworld(str){ console.log(str); }; function _hellombsh(str){ console.log(str); }; return{ helloworld: _helloworld, hellombsh: _hellombsh }; })(); //使用插件 plugin.helloworld('HelloWorld!') //输出我们久违的‘HelloWorld!’ plugin.hellombsh('欢迎来到梦笔生花!') //输出我们激动人心的‘欢迎来到梦笔生花!’ ok!这就是插件,我们扩展了插件增加了hellombsh方法,就这么简单。 这是一种比较简洁好用的自定义插件方式,还有其他不同写法,摘抄几段仅供参考:
1.面向对象思想 类方式 //自定义类 function plugin(){} //提供默认参数 plugin.prototype.str = "default param"; //提供方法(如果不传参,则使用默认参数) plugin.prototype.firstFunc = function(str = this.str){ alert(str); } //创建"对象" var p = new plugin(); //调用方法 p.firstFunc("Hello ! I am firstFunc");//Hello ! I am firstFunc p.firstFunc();//default param
2.闭包方式 var plugin =(function(){ function _firstFunc(str){ alert(str); }; return{ firstFunc: _firstFunc, }; })();
3.第二种方式上的一些变化 貌似更加规范? (function(){ //定义一些默认参数 var _options={ default_word:"default hello" } //定义一些api var _plugin_api = { firstFunc:function(str = _options.default_word){ alert(str); return this;//返回当前方法 }, secondFunc:function(){ alert("secondFunc"); return this;//返回当前方法 } } //这里确定了插件的名称 this.CJPlugin = _plugin_api; })(); CJPlugin.firstFunc("hello");//hello CJPlugin.firstFunc();//default hello CJPlugin.secondFunc();//secondFunc
好了,javascript的自定义插件和闭包就介绍到这里,任何语言的任何知识点深入研究都是变化无穷 妙用无穷的,希望本文能够为广大js爱好者更好地理解闭包和插件尽些绵薄之力。