函数

函数是对代码的抽象和封装,相当于丰富了语言本身

用函数把一些常用的处理代码封装起来,可以使用者不必再关注这些代码的细节,

只需要使用和依赖这个黑盒子就行了,

如果我们的项目建立在这些黑盒子上,将会降低我们项目的复杂度,所以再开开始项目的时候要尽量选择一些可靠的函数库,让他们成为你的房子的基石。

 

js 引擎在执行js 代码的时候,会首先创建一个全局作用域,有的叫做全局执行上下文,都他妈一样,你可以把这个全局作用域,想象成个 对象, 该对象上面预存了一些常用的方法和属性,比如 

全局作用域 {
      window: 自身,
      Array
      parseInt
    
      ......
}

等等

当遇到一些属性的访问,或者访问时候会查询该玩意

 

js 中除了全局作用域就只有函数作用了,后来又有了局部作用域 let 搞出来的。

在全局作用域中定义函数 function A (a, b) {}

函数A,会保存自己定义时候所在的作用域

相当于A.scop = {

   全局作用域

}

当函数被调用的时候,会创建自己的作用域

A()

{

  A函数作用域,该作用域有函数内声明的变量,形式参数

  a,

  b

  arguments

  等

  scope : 全局作用域

} 

当函数内遇到变量 c , 首先在自己作用域里面查找c ,如果没有被定义,则按照自己定义时候保存的作用域链查找上一个作用域看有没有,直到全局。

 

function A () {

  functionB() {}

   。。。。

   。。。。。

       B()

}

上面代码当函数A调用的时候,函数B被定义,同时保存了 函数A的作用域,

即B.scope = {

    函数A的作用域

  scope : {全局作用域}

}

当函数B被调用的时候,就会形成一个作用域链条

{

  函数B的作用域

  scope: {

    函数A的作用域

    scope: {

      全局作用域

    }

},

当执行B函数的时候,遇到一个变量,就会按照上面的作用域链条查询到全局,左后没有undefind

闭包的形成

function A () {

   var c = 1;

   var d = 2;

   xxxx

  return functionB () {}

}

 

var  f =  A ();

当 B函数在A函数中定义的时候保存了 A的作用域,最后A 函数把B retrun 出去给了变量 f;

变量f 引用了 B函数, 而B函数本身scope属性保存了A的作用域,导致A函数即使执行完了他的作用域 {

  A作用域

},依然存活在堆内存中,无法销毁

但是呢该作用域,又被B的作用域保存了 {

    B的作用域

    scope :  {

      A作用域

      c: 1,

      b: 2

    }

}

 

所以在f 调用的时候可以通过作用域链,肆意攀爬到A中声明的任何变量,方法,那么外层函数的作用域也就相当于了,内层存函数的一个私有小仓库,自己可以去里面存取任何东西,封装私有物品到里面去,外面任何地方访问不了,这就是闭包。所以函数可以利用闭包存储一些状态,而不是让自己是一个被调用完就完全消失过程,闭包让一个函数可以媲美对象

 

函数中this

通过上面的可以知道,函数其实跟调用时候的上下文没什么关系, 因为函数在定义的时候,已经通过作用链保存了自己能够访问的作用域,如果如此,那么函数就是一个封闭的,跟调用它的上下文完全没关系的一段代码,这样的函数会非常的死板,不能达到我们想要的灵活效果,

所以函数里面有了this 指针,用来跟函数跳用的上下文扯上关系,以便函数内部的代码能够处理改变调用上下文中的一些数据,

所以this 在函数中变成一个跟调用方式有关系的变量

如果一个函数作为函数调用,它内部this 指向全局对象, 如果做为对象的方法调用,那么函数认为自己里面的处理是用来针对这个对象的,所以this, 指向调用它的对象,以便方便处理对象,改变对象的状态。

 

有时候this,因为动态指定的关系,也会带来麻烦,应为调用的关系指到了我门不想让它指定的对象上,所以有了call  和apply 

这两个方法可以将函数的this 绑定死在某个对象上,而不再根据调用方式乱指向,从而得到一个稳定完全跟调用方式没有关系的函数,所以你就不用担心你的函数会有副作用了。

箭头函数的this, 箭头函数中没有this,  当你访问箭头函数中的this的时候 其实会访问到该函数定义时候所在作用域中this.

 

函数可以作为参数传递的意义

函数可以作为函数参数传入,意为着你可以把一部分变化的不稳定的逻辑,让用户用函数传入,这样就可以分离业务代码中的变与不变,一个稳定的函数,却可以根据传入的回调,表现出仪态万方,增强了语言的表达力。

 

const appendDiv = function() {
    for (let i = 0; i < 100; i++) {
        let div = document.createElement('div');
        div.innerHTML = i;

        document.body.appendChild(div);
        div.style.display = 'none'
    }
}

该段代码,div.style.display = 'none'的逻辑硬编码在appendDiv里,显然是不合理的,使该段代码难以复用的函数,并不是每个人创建了节点之后都希望隐藏它。

所以要把这段代码抽出来,用回调函数的形式传入

const appendDiv = function(cb) {
    for (let i = 0; i < 100; i++) {
        let div = document.createElement('div');
        div.innerHTML = i;

        document.body.appendChild(div);

        if(typeof cb === 'function') {
            cb(div);
        }
        
    }
};
appendDiv((node) => {node.style.display = 'none'});

用回调以后,对添加到页面的节点的处理,灵活性变强,函数本身的复用性变强。

 call ,apply

在js中是可以互接老婆的,如果一个对象觉的另一个对象的方法不错,那么就可以直接借来用

const obj1 = {
    name: 'seven'
};

const obj2 {
    getName() {
        return this.name;
    }
};

obj2.getName.call(obj1); //输出结果seven

Array.prototype.push.call(arguments, 4); //借用Array.prototype上的push方法

我们的预期中,Array.prototype 上方法本来只能用来操作 数组对象,但是用call 和apply 可以把任意的对象绑定到该方法的this上,那么该方法内部根据this展开的操作,就会作用到这个绑定的对象上,跟该对象自身的方法一样,因为对象自身方法也是通过thisl来访问自身,并对自己做处理。所以借来的跟自己方法效果一摸一样。

这样也会导致函数内this泛化的问题,根据调用的方式就指向不同的对象,这样也会造成一个函数的不稳定。

 

高阶函数

AOP(面向切面编程)的主要作用是把一些跟核心业务逻辑模块无关的功能抽离出来,这些跟业务逻辑无关的功能通常包括日志统计、安全控制、异常处理等。把这些功能抽离出来之后,再通过“动态织入...参入到业务逻辑模块中,这样做的好处首先是可以保持业务逻辑模块的纯净和高内聚性,其次可以很方便的复用日志统计等功能模块

Function.prototype.before = function(beforefn) {
    let self = this; //保存函数本身

    return function() {
        beforefn.apply(this, arguments); //执行新函数

        return self.apply(this, arguments);
    }
}

Function.prototype.after = function(afterfn) {
    let self = this;

    return function() {
        let ret =  self.apply(this, arguments);
        afterfn.apply(this, arguments);
     
     return ret
} };

var fun = function() {console.log(2)};
fun = fun.before(() => console.log(1)).after(() => console.log(3));
fun();



 

 

函数柯里化    又称部分求值,一个currying的函数首先会接受一些参数,接受这些参数之后,该函数并不会立即求值,而是继续返回另外的一个函数,刚才传入的参数在函数形成的闭包中被保存起来,待到函数真正需要求值的时候,之前传入的所有参数都会被一次性用于求值

const monthlyCost  =  0; //每月总花费

const cost = function(money) {monthlyCost += money};


cost(100); // 第一天
cost(200); // 第二天
cost(300); // 第三天

//。。。。
console.log(monthlyCost);



const cost = (function() {
    let args = [];


    return function() {
        if (arguments.length === 0) {
            let money = 0;

            for (let i = 0, l = args.length;  i < l; i++) {
                money += args[i];
            }

            return money
        }else {
            [].push.apply(args, arguments);
        }
    }
})()
cost(100);
cost(200);

console.log(cost()); //输出值为三百

 

职责分离

const currying = function (fn) {
    let args = [];

    return function() {
        if (arguments.length === 0) {
            return fn.apply(this, ars)
        }else {
            [].push.appy(args, arguments);
        }
    }
}

const cost = (function() {
    let money = 0;

    return function() {
        for(let i = 0, l = arguments.length; i < l; i++) {
            money += arguments[i];
        }

        return money;
    }
})()

var cos = currying(cost);
cos(100);
cos(200);
cos(300);
//以上都没真正求值
console.log(cos());

 

函数节流

const throttle = function(fn, interval) {
    let self = fn; //保存需要被延迟的函数引用
    let timer;
    let firstTime = true; //是否为第一次

    return function () {

        let args = arguments;

        let me = this;


        if (firstTime) { //如果为第一次调用,不需要延迟执行
            self.apply(me, args);

            return firstTime = false;

        }


        if (timer) {
            return false
        };

        timer = setTimeout(() => {
            clearTimeout(timer);
            timer = null;

            self.apply(me, args);

        }, interval || 500);
    }
}

window.onresize = throttle(function() {
  consle.log(1);
}

 

分时函数

const renderFriendList = function(data) {
    for (let i = 0, l = data.length; i < l; i++) {
        let div = document.createElement('div');
        div.innerHTML = i;
        document.body.appendChild(div);
    }
}

renderFriendList(ary);

const timeChunk = function(ary, fn, count) {
    let obj;
    let t;

    let len  = ary.length;

    let start = function() {
        for (let  i = 0; i < Math.min(count || 1, ary.length); i++) {
            let  obj = ary.shift();
            fn(obj)
        }
    };


    return function() {
        t = setInterval(function() {
            if (ary.length === 0) {
                //如果全部节点都已经被创建好

                retrun  clearInterval(t);

                start();
            }
        }, 200)
    }
}
let arry = [];

for (let i = 1; i <= 1000; i++) {
    ary.push(i);
}

const renderFriendList = timeChunk(ary, function(n) {
    let  div = document.createElement('div');
    div.innerHTML = n;

    document.body.appendChild(div);
}, 8);

 

5.惰性加载函数

let addEvent = function(elem, type, hanlder) {
    if (window.addEventListener) {
        return elem.addEventListener(type, hanlder, false);
    }

    if (window.attachEvent) {
        return elem.attachEvent('on' + type, hanlder);
    }
}

该函数的缺点是每次被调用都会执行里面的分支,虽然if 分支开销不大,但是又方法可以让程序避免这些重复的执行过程

let addEvent = function(elem, type, hanlder) {
    if (window.addEventListener) {

        return function (elem, type, hanlder) {
            elem.addEventListener(type, hanlder, false);
        }
    }

    if (window.attachEvent) {

        return function (elem, type, hanlder) {
            elem.attachEvent('on' + type, hanlder);
        }
    }
}

 

转载于:https://www.cnblogs.com/shengdouhun/p/9481517.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值