练手写函数

  • 封装Lodash库里的get方法
  • 防抖函数vs节流函数
  • 封装call
  • 简单的三种继承方式
  • 快速排序

封装lodash的get方法

// 给定一个对象和一个路径,得到路径对应的值
// 输入输出样例
// 样例一
// 输入:get({a: 1}, 'a')
// 输出:1
// 样例二
// 输入:get({a: [1, {b: 2}]}, 'a[1].b')
// 输出:2
// 'a.b.c.b.c.d' 

function get(obj, param) {
  eval(`const x = ${JSON.stringify(obj)}; this.ret = x.${param}`);
  return this.ret;
}

eval()函数的使用:

在这里插入图片描述

防抖函数

  • 防抖函数与节流函数的区别及使用场景
  • 防抖函数的实现为什么用了柯里化和闭包

防抖类似电梯关门,每10s钟关一次门,当10s内又有人按开门,则关门的10s清零重新计算,所以当10s总是有人按开门,电梯门永远不能成功关闭,所以说防抖函数设置的回调执行的时间应小于时间执行的频率。
防抖函数使用场景如:

  • 表单提交
  • 对于输入框连续输入进行AJAX验证时,用函数防抖能有效减少请求次数
  • 判断scroll是否滑到底部,滚动事件+函数防抖

防抖函数的实现思想,实际上就是将多次触发的时间延迟到一定时间之后执行。既定时调用回调函数。

function debounce(fn, wait) {
	var timer = null;
	return function () {
		var args = arguments;
		var context = this;
		if (timer) {
			clearTimeout(timer);
			timer = null;
		}
		timer = setTimeout(() => {fn.apply(context, args)}, wait);
	}
}


节流函数:上一次执行时间和此次执行时间差值小于规定时间,则不执行。

function throttle(fn, time) {
	let _lastTime = null;
	return () => {
		const _nowTime = + new Date();
		if (_nowTime - _lastTime > time || !time) {
			fn();
			_lastTime = _nowTime;
		}
	}
}

fn() {
	console.log('防抖');
}

//调用
setInterval(throttle(fn, 1000), 10);

对比总结一下防抖函数和节流函数的区别:

  1. 防抖:可以理解为一定时间内触发多次事件,合并成一次执行。要注意的就是,当回调函数触发频率高于延迟时间,防抖函数则一直不能被触发。
  2. 节流:可以理解为缩小事件的执行频率。

封装一个call:call是用来改变this指向的。

思想:给foo对象增加一个属性,属性的方法是调用的函数。这个时候函数的this就指向了想指向的对象上。但是这样却给 foo 对象本身添加了一个属性,所以需要用 delete 再删除它。

所以我们模拟的步骤可以分为:

  1. 将函数设为对象的属性
  2. 执行该函数
  3. 删除该函数
//封装思想:
function bar () {
	console.log(this.value);
}
var foo = {
	value: 'hyt'
}
bar.call(foo);

//实现:
var testObj = {
	value: 'wl',
	testFn: function () {
		console.log(this.value);
	}
}
testObj.testFn(); // wl
delete testObj.testFn;
console.log(testObj);

//封装成品:
Function.prototype.call2 = function (context) {
	context.fn = this; //this是调用call的函数,既bar();
	context.fn();
	//考虑不能丢失bar函数本身传进来得参数;记得要从arguments数组的第二个位置取值哦
	var args = [];
	for (var i = 1; i < arguments.length; i++) {
		args.push(arguments[i]);
	}
	var result = eval('context.fn(' + args + ')');
	delete context.fn;
	return result;
}

bar.call2(foo);

//封装apply,这个是张yixiong的方法,我看着有点绕,不过比我写的高级一点:
Function.prototype.apply = function (context, args = []) {
  const target = Object(context);
  const thisSymbol = Symbol();
  target[thisSymbol] = this;
  const result = target[thisSymbol](...args);
  delete target[thisSymbol];
  return result;
};

这里有加入arguments对象的处理主要是考虑到bar函数传入得其他参数,现在简单介绍一下arguments对象是干什么的。

arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。

例如,如果一个函数传递了三个参数,你可以以如下方式引用他们:
arguments[0],arguments[1],arguments[2]…

function test () {
	var len = arguments.length;
	var sum = 0;
	for (var i = 0; i < len; i++) {
		sum += arguments[i];
	}
	return sum;
}
test(1,2,3,4);//10

值得注意的是,arguments是一个伪数组,只具有length属性,和索引元素外没有任何数组的属性,如map、reduce、pop等方法,并且在箭头函数中不能使用arguments。


继承
构造继承:

function Animal(name) {
	this.name = name;
	this.sleep = () => {
		console.log('睡觉');
	}
}
Animal.prototype.eat = food => {
	console.log('eat' + food);
}
function Cat() {
	Animal.call(this);
	this.name = 'kavin';
}
var cat = new Cat();
console.log(cat instanceof Animal);
console.log(cat instanceof Cat);
console.log(cat.name);
console.log(cat.eat());
console.log(cat.sleep());

原型继承:父类的实例是子类的原型

function Animal(name) {
	this.name = name;
	this.sleep = () => {
		console.log('睡觉');
	}
}
Animal.prototype.eat = food => {
	console.log('eat' + food);
}
function Cat () {
}
Cat.prototype = new Animal();
var cat = new Cat();
console.log(cat.sleep());
console.log(cat.eat());

实例继承:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型);

function Cat() {
	var instance = new Animal();
	return instance;
}
var cat = new Cat();
console.log(cat instance Animal);
console.log(cat instance Cat);

快速排序

var quicksort = function(arr) {
	if (arr.length <= 1) {
		return arr;
	}
	var middle = Math.floor(arr.length / 2);
	var midNum = arr.splice(middle, 1)[0];
	var left = [];
	var right = [];
	var newArr = [];
	for (var i = 0; i < arr.length; i++) {
		if (arr[i] < midNum) {
			left.push(arr[i]);
		} else {
			right.push(arr[i]);
		}
	}
	return quicksort(left).concat([midNum], quicksort(right));
}
快排思想:

 1. 选出数组中间为数作为基准。
 2. 生成左右两个指针,循环遍历数组,比基准大的数放在左边,反之放右边。
 3. 利用递归当指针数组长度等于1时,返回新数组。


slice(start, end),截取数组中的一段; splice(index, howmany, ''); 方法向/从数组中index的位置开始添加/删除homany个项目,然后返回被删除的项目。这两个数组的方法不要混淆哦!

心得:
在实现快排、斐波那契数、数组扁平化等场景中都会用到递归算法,我将抽时间整理出用到递归算法的各种场景,以便补充我对递归算法的熟悉程度。
最近在复习一些js的基础知识,比如原型链、 闭包、this指向、执行上下文,以及一些常用功能函数,比如防抖节流、递归、归并排序我发现我想问题都不是很清楚,思考了原因大概是上学的时候没好好学数学,导致想问题很慢,时常感觉自己不如别人聪明。
所以我决定未来花时间恶补大学欠下的数学知识和算法,追上别的同学。
对了,发现FF同学基本功很扎实,她很踏实的看完了很多js相关书籍,我觉得我也要克服一下浮躁懒惰的问题,开始深入看一些专业书籍。并且养成深入思考的习惯。
懒于思考,会花费我更多时间,只考死记硬背记住一些答案,却在一段时间不用后,又会忘掉,我觉得我要克服的问题还挺多的。

  • 养成深入阅读技术书的习惯
  • 善于找到好的知识资源
  • 勤于思考
  • 归纳总结
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚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
完整版: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 。。。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值