js高阶编程技巧
js高阶编程技巧的核心就是利用闭包,实现一些高阶编程的方式 那么,属于js高阶编程方式都有哪些呢?
模块化思想
模块化思想的发展经过了单例模式->AMD->CMD->CommonJS->ES6Moudle几个里程碑 在js中,模块化思想的好处就是便于封装,在协同工作的模式下,保护了各个人员之间的代码与全局作用域中的变量不互相污染。
(function(){
let time=0;
function changeTime(){
time++;
}
})();
上面的代码使用闭包的方式实现了对其的保护,不会污染全局变量
(function(){
let time=0;
function changeTime(){
time++;
}
window.changeTime=changeTime;
})();
window.changeTime=changeTime;
将方法changeTime暴露给全局作用域,以供他人调用。但是如果挂载的过多,就会可能造成污染
js对象的特点是,每一个对象都是一个单独的堆内存空间
仿照其他后台语言,其实obj1,obj2不仅仅是对象名,还被成为命名空间
每一个对象都是一个单独的实例,用来管理自己的私有信息,即使名字相同,也互不影响,其实这就是js中的单例模式
var obj1={
name:"rose",
age:18,
fn:function(){
//.....
}
}
var obj2={
name:"jack",
age:18,
fn:function(){
//.....
}
}
前面的解决
var Time = (function(){
let time=0;
function changeTime(){
time++;
}
return{
changeTime
}
})();
//自执行函数执行之后返回一个对象被Time引用,其开辟的栈内存空间不能释放,形成了一个闭包。外界想要调用changeTime方法的时候,直接使用Time.changeTime即可,这样就不会污染全局环境。
以上模式就是高级单例设计模式(闭包+单例)也是最早期的js模块化思想。
惰性函数
惰性函数就是懒的意思,想要代码尽量少,执行尽量少,内存消耗尽量少。
例如:
返回样式对象的api
window.getComputedStyle()
,但是这个api并不兼容ie,ie中有自己的api dom.currentStyle()
来获取样式对象。
function getCss(element,attr){
if("getComputedStyle" in window){
return window.getComputedStyle(element)[attr];
}
return element.currentStyle[attr];
}
但是,我们在每次使用 getCss()
这个函数的时候,就会执行一次getComputedStyle" in window
,我们知道,我们没有换浏览器,所以每次执行的结果都相同,再次执行getComputedStyle" in window
,没有必要,惰性思想要做的就是能一次解决的事情,不会再做第二次。
优化:
let flag="getComputedStyle" in window
function getCss(element,attr){
if(flag){
return window.getComputedStyle(element)[attr];
}
return element.currentStyle[attr];
}
但是这个flag变量进入全局变量空间了,通过学习前面的单例模式,我们知道这样写其实不太好。接下来,看下面的代码。
再优化
let getCss=function (element,attr){
if("getComputedStyle" in window){
getCss = function(element,attr){
return window.getComputedStyle(element,attr);
}
}else{
getCss = function(element,attr){
return element.currentStyle[attr];
}
}
}
这样我们发现第一次执行并不会出效果。再优化
let getCss=function (element,attr){
if("getComputedStyle" in window){
getCss = function(element,attr){
return window.getComputedStyle(element,attr);
}
}else{
getCss = function(element,attr){
return element.currentStyle[attr];
}
}
return getCss(element,attr)
}
结束!
柯里化函数
是一种预先处理的思想,形成一个闭包,将一些值(未来会使用)保存起来。所有符合这种模式的,都叫做柯里化函数。
下面我们以一道题展开:
// 普通的add函数
function add(x, y) {
return x + y
}
add(1, 2) // 3
curryingAdd(1)(2)() // 3
要实现上面代码中的效果,curryingAdd
函数要如何编写呢
上面我们说到,函数柯里化是用闭包将一些值保存起来以供未来使用。
function curryingAdd(...params) {
let args = [...params];
return function inner(...arguments) {
args = args.concat(arguments);
return eval(args.join("+"));
};
}
console.log(curryingAdd(1, 2)());//3
console.log(curryingAdd(1, 1)(1, 1);//4
这里,我们将传进来的值放进数组args
中保存,返回一个函数inner
,这样就可以二次调用。那么如何实现三次甚至四次多次连续不定次调用呢?比如
console.log(curryingAdd(1, 1)(1, 1)(2, 2)());//8
这时我们就需要再inner
函数中做一些处理,如下所示:
function curryingAdd(...params) {
let args = [...params];
return function inner(...arguments) {
args = args.concat(arguments);
if (arguments.length == 0) {
return eval(args.join("+"));
} else {
return inner;
}
};
}
console.log(curryingAdd(1, 2)());
console.log(curryingAdd(1, 1)(1, 1)());//4
console.log(curryingAdd(1, 1)(1, 1)(2, 2)());//8
我们通过判断inner
函数值的有无来判断是返回结果还是继续返回函数。如果arguments
参数长度为0,说明已经没有参数可以使用了,那么返回args
中值相加的结果,如果arguments
中仍旧有参数,那么就返回函数inner
,以供接着向args
中追加参数。
compose组合函数
在函数式编程中有一个很重要的概念就是函数组合,实际上就是把处理函数像管道一样连接起来。然后让数据穿过管道得到最终的结果。例如:
const add1=(x)=>x+1;
const mul3=(x)=>x*3;
const div2=(x)=>x/2;
div2(mul3(add1(add1(0))))//=>3
上面的那中写法可读性明显太差了,我们可以构建一个compose函数,它接收任意多个函数作为参数(这些函数都只接受一个参数),然后compose函数返回的也是一个函数,达到以下的效果。
const operate=compose(div2,mul3,add1,add1);
operate(0)//相当于div2(mul3(add1(add1(0))))//=>3
operate(2)//相当于div2(mul3(add1(add1(2))))//=>3
那么compose
函数应该怎样写呢?
const add1 = (x) => x + 1;
const mul3 = (x) => x * 3;
const div2 = (x) => x / 2;
function compose(...funs) {
return function(arg) {
for (let i = funs.length - 1; i >= 0; i--) {
arg = funs[i](arg);
}
return arg;
};
}
let operate = compose(div2, mul3, add1, add1);
console.log(operate(0));//3
同样是使用闭包的思想,将存储进去的函数保存起来,待operate()调用的时候就可以使用保存的函数进行运算。返回运算结果。
优化:
const add1 = (x) => x + 1;
const mul3 = (x) => x * 3;
const div2 = (x) => x / 2;
function compose(...funs) {
return function(arg) {
if (funs.length === 0) return arg;
for (let i = funs.length - 1; i >= 0; i--) {
if (typeof funs[i] != "function") continue;
arg = funs[i](arg);
}
return arg;
};
}
let operate = compose(div2, mul3, add1, add1);
console.log(operate(0));
另外一种实现方案
const add1 = (x) => x + 1;
const mul3 = (x) => x * 3;
const div2 = (x) => x / 2;
function compose(...funs) {
if (funs.length === 0) {
return (arg) => arg;
}
if (funs.length == 1) {
return funs[0];
}
//a:初始值或者计算结束后返回的值,b当前值
return funs.reduce((a, b) => {
return (...args) => a(b(...args));
});
}
let operate = compose(div2, mul3, add1, add1);
console.log(operate(0));//3
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!