JavaScript知识点记录
记录方法及知识点,避免后期遗忘
API:
参考手册:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference
标准类库:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects
类型
Javascript中一共有六种主要类型
- string
- number
- boolean
- null
- undefined
- object
注意:类型本身并不是对象。常见的错误说话就是:javascript中万物皆是对象
javascript中还有一些对象子类型,通常被称为内置对象。
- String
- Number
- Boolean
- Object
- Function
- Array
- Date
- RegExp
- Error
在Javascript中,他们实际上是一些内置函数,这些函数可以当做构造函数使用。
null和undefined
null代表一个空值,undefined代表值未定义。
==和===
==会自动转换数据类型再比较。===不会自动转换数据类型,如果数据类型不一致,则返回false。
例如:false == 0 : true,false === 0:false
数组
var arry = new Array(1,2,3);
var array = [1,2,3];
对象
var model = {
name:"Chenxy"
age:20
}
Json
var model = {
"Name": "Chenxy",
"hooby": ["Eat", "Play", "Game"]
}
strict模式与全局变量
如果变量不用var申明,则视为全局变量。如存在多个同名的全局变量则会冲突。
为修复此问题,推出strict模式,如未声明则异常。启动方法为在js代码上加上 'use strict';
转义字符
\n 换行,\t 制表符,\\ 就是\
字符串方法
var ToUpper = strText.toUpperCase(); console.log("全部变大写:"+ToUpper); var ToLower = strText.toLowerCase(); console.log("全部变小写:"+ToLower); var IndexOf = strText.indexOf("jq"); console.log("返回指定字符出现的位置,如果没有则-1:"+IndexOf); var SubStr = strText.substring(0,3); console.log("返回指定区间字符串:"+SubStr);
数组方法
var arr = [10,20,30,'40']; var IndexOf = arr.indexOf(20); console.log("返回指定的索引,如果没有则-1:"+IndexOf); var Slice = arr.slice(2,3); console.log("截取部分元素,返回一个新的array,如果不写第二个则默认截取到最后:"+Slice); arr.push(50,60); //向末尾添加若干元素 arr.unshift(5,6); //向头部添加若干元素 arr.pop();//删除最后一个元素 arr.shift();//删除第一个元素 arr.sort(); //排序 arr.reverse(); //倒序 arr.splice(2,3,80,90); //从索引2开始删除三个元素,然后添加两个元素 var arr2 = ['A','B','C']; arr.concat(arr2); //合并两个数组 arr.concat(1,2,[3,4]); //自动将数组拆开,并组合 var join = arr.join('-'); console.log("每个元素都用指定连接符连接:"+join);
in操作符
查询对象中是否包含某一个属性。包含为true,反之为false。
例子:'name' in obj;
Map和Set
一组键值对的结构,拥有极快的查找速度。键不可以重名,如果重名则会替换之前那个
var sMap = new Map(); //初始化空Map sMap.set("A",67); //添加一个 sMap.set("B",70); sMap.has("A"); //判断是否存在 sMap.get("A"); //获取对应值 sMap.delete("A"); //删除key
Set没有重复的Key,重复元素会被自动过滤。剩下的和Map相同
arguments
调用者传入的所有参数。直接方法里面写即可
(function(){ Function.prototype.Go = function(){ console.log(arguments); } var result = function(){}; result.Go(1,2,3); })()
rest
多余的参数以数组的形式交给变量rest。例:function a(a,b,..rest){}
this
只获取被调用的对象。
apply
修复this指向对象。两个参数,第一个是需要绑定的this变量,第二个是参数。例子:getA.apply(xiaoming,[1,2,3]); //this指向小明,参数为123
call
跟apply相似,只不过是顺序输入。getA.call(xiaoming,1,2,3);
装饰器
利用apply,可以重写window内置方法。举例:
var oldParInt = window.parseInt; window.parseInt = function(){ alert(1); return oldParInt.apply(null,arguments); }
Map
遍历于数组,可以让数组中每个元素都执行某个方法。例:
function pow(x) { return x*x; } var arr = [1,2,3,4,5,6]; arr.map(pow);
reduce
函数必须接收两个值,遍历与数组,进行累加计算。例:
function pow(x,y) { return x*y; } var arr = [1,2,3,4,5,6]; arr.reduce(pow);
filter
过滤某些元素,返回剩下的元素。例,删除偶数只留下奇数:
var arr = [1,2,3,4,5,6];
var r = arr.filter(function(x){
return x % 2 != 0;
});
console.log(r);
闭包私有变量
用javascript实现一个私有变量的效果,如下:
function ZiZeng(x) {
var z = x || 0;
return {
add: function() {
z += 1;
return z;
}
}
}
var zi = ZiZeng();
console.log(zi.add(1));
generator
除了return以外,可以返回多次使用yield。例子:循环输出效果
function* AddNum(max)
{
var qishi = 0;
while (qishi < max){
yield qishi;
qishi++;
}
return qishi;
}
for(var x of AddNum(5))
{
console.log(x);
}
注意:function*
typeof 与 instanceof
typeof 返回对象类型,例:typeof 1; //'number'
instanceof 用于判断一个变量是否某个对象的实例,例:"chenxy" instanceof String; //true
new object与object
var n = new Number(123); //实际上类型已经是object,所以类型尽量不要加new
var n = Number('123'); //转换为Number类型,类似于方法parseInt()
数字转换字符串
123.toString(); //异常,应写为 123..toString() 或 (123).toString()
正则表达式
\d 匹配数字,
\w 匹配字母或数字,
\s Tab或者空格
. 匹配任意字符,
* 任意个字符(包括0个),
+ 表示至少一个字符,
? 表示0或1个,
{n} 表示n个,
{n,m} 表示n-m个
[] 表示范围,比如:[0-9a-zA-Z\_] 可以匹配一个数字、字母或者下划线
A|B 匹配A或B,例如:[J|j]ava 可以匹配 Java 或 java
^表示行开头,例如:^\d
$表示行结束,例如:$\d
代码 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
代码/语法 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
代码/语法 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字母以外的任意字符 |
Javascript中,两种方法可以定义正则表达式
第一种:直接写,var a = /ABC\-001/;
第二种:实例化一个RegExp,var a = new RegExp('ABC\\-001');
判断是否匹配
var re = /^\d{3}$/;
re.test('000'); //true
切分字符串
'a b c d'.split(/\s+/); //['a','b','c']
分组
()表示要提取的分组。匹配成功以后会返回一个Array,第一个是本身,后面是匹配成功的字符串。例如:
var re = /^(\d{3})-(\d{3,8})$/;
re.exec('010-123456'); //['010-123456','010','123456']
Json
Json一个六种数据类型。number、boolean、string、null、array、object。
定死了字符串必须是 UTF-8,必须用双引号
序列化
var xiaoming = {
name:'晨星宇',
age:22,
skills:['Javascript','C#','Oracle']
};
console.log(JSON.stringify(xiaoming));
//{"name":"晨星宇","age":22,"skills":["Javascript","C#","Oracle"]}
console.log(JSON.stringify(xiaoming,null,' '));
//格式化
console.log(JSON.stringify(xiaoming,['name','skills']));
//筛选键值,{"name":"晨星宇","skills":["Javascript","C#","Oracle"]}
还可以传入一个函数,这样每个键值都会被函数先处理
function convert(key, value) {
if (typeof value === 'string') {
return value.toUpperCase();
}
return value;
}
JSON.stringify(xiaoming, convert, ' ');
还可以自定义一个toJson方法,直接返回序列化的数据
var xiaoming = {
name:'晨星宇',
age:22,
skills:['Javascript','C#','Oracle'],
toJSON:function(){
return {
"Name":this.name,
"Age":this.age
};
}
};
反序列化
console.log(JSON.parse('{"name":"晨星宇","age":22,"skills":["Javascript","C#","Oracle"]}'));
Javascript入门易,精通难,基本上是共识的一个观点。在这个篇幅里,主要对一些难点进行记录。
鸭子类型
Javascript属于动态类型语言的一种。对变量类型的宽容,给了很大的灵活性。由于无需类型检测,则无需考虑他是否被设计拥有该方法。
鸭子类型通俗说法:如果它走起路来像鸭子,叫起来也是鸭子,那么他就是鸭子
鸭子类型指导我们只关注对象的行为,而不关注对象本身。关注HAS-A 而不是 IS-A。
如下例子,不管什么动物,只要他会duckSinging,并且是方法,就可以加入。
var duck = {
duckSinging: function () {
console.log("鸭子叫");
}
};
var chicken = {
duckSinging: function () {
console.log("鸭子叫");
}
};
var joinChoir = function(animal){
if(animal && animal.duckSinging instanceof Function)
{
//可以加入
}
}
多态
同一个操作用于不同的对象上,可以产生不同的解释和不同的结果。举例:动作都会叫,那么叫就是操作。猫叫和狗叫的结果不一样,这就是多态。
Sound是同一个操作,所以使用prototype来在原型链上进行定义。将Cat生成为方法,是为了给他的原型链添加方法。如Dog就不属于多态。
!(function () {
var makeSound = function (animal) {
animal.Sound();
};
var Cat = function(){};
Cat.prototype.Sound = function () {
console.log("喵");
};
var Dog = {}; //不属于多态
Dog.Sound = function () {
console.log("汪");
}
makeSound(Dog);
})()
一种动物能否发出叫声,取决于他有没有Sound方法,而不是取决于他是那种对象。不存在任何类型耦合,这就是鸭子类型的典型。
原型模式
原型模式是通过克隆来创建对象的。我们只需要调用克隆方法,就可以完成功能。使用Object.Create方法,来实现克隆。
!(function () {
var Plance = function () {
this.blood = 100
};
var plane = new Plance();
plane.blood = 200;
var clonePlane = Object.create(plane);
console.log(clonePlane.blood);
})()
可以重写拷贝方法,来进行自定义
Object.create = Object.create || function(obj){ //Object.create || 意思是如果没有此方法
var F = function () {};
F.prototype = obj;
return new F();
};
继承
原型编程的基本规则
1.所有的数据都是对象
2.要得到一个对象,需要找到一个对象作为原型进行克隆。
3.对象会记住他的原型
4.如果对象无法响应某个请求,则会把这个请求委托给它自己的原型
javascript中绝大多数数据都是对象,除了undefined之外,都可以通过包装类的方式编程对象类型数据。
javascript中根对象是Object.prototype对象,他是一个空的对象。任何对象都是通过这个克隆而来的。
创建关联
var foo = { something:function(){ console.log("foo"); } }; var foo2 = Object.create(foo); foo2.something(); //foo
if (!Object.create) {
Object.create = function (o) {
function F() {
}
F.prototype = 0;
return new F();
};
}
var obj = function(){};
var obj1 = {};
console.log(Object.getPrototypeOf(obj) === Function.prototype);
console.log(Object.getPrototypeOf(obj1) === Object.prototype);
Javascript中没有类的概念,那么new Person()这种,实际上是调用他的函数构造器,来进行初始化。函数既可以作为普通函数,也可以作为构造器。
!(function () {
var obj = function(na){
this.name = na;
};
var obj1 = new obj();
var obj2 = new obj('a');
console.log(obj1.name); //undefined
console.log(obj2.name); //a
})()
请求可以在链条中往后传递,那么每个节点都必须知道它的下一个节点。Javascript给对象提供了一个名为_proto_的隐藏属性。
这个属性会默认指向它的构造器的原型对象。
var obj = function(na){};
console.log(obj.__proto__ === Function.prototype); //true
当对象无法响应某个请求的时候,他会顺着原型链把请求传递下去,直到有可以处理的请求对象为止。
以下是最常用的原型继承
首先obj2找,然后obj2对象构造器原型obj1原型,obj1原型找obj原型
!(function () {
var obj = function(){};
obj.prototype = {name:'sven'};
var obj1 = function () {};
obj1.prototype = new obj();
var obj2 = new obj1();
console.log(obj2.name); //sven
})()
对象构造器创建与对象克隆
对象构造器创建,只会创建该对象实体,不会创建该对象对应的原型。而克隆则是将原型也一并拷贝过去。
!(function () {
var obj1 = function(){
this.name = 'sven'
};
var obj2 = obj1;
var obj3 = Object.create(obj1);
var obj4 = new obj1();
console.log(typeof obj2.prototype); //object
console.log(typeof obj3.prototype); //object
console.log(typeof obj4.prototype); //undefined
})()
this
this总是指向一个对象,对象是在运行时基于函数执行环境动态绑定的。
this指向大致分为四种
1.隐示绑定:作为对象调用时,this指向该对象。
var obj = {
a:1,
getA:function()
{console.log(this.a);}
};
obj.getA(); //1
2.普通函数:作为普通函数调用时,this指向windows对象。
window.a = 1;
var getA = function(){
return this.a;
};
console.log(getA()); //1
3.构造调用:作为构造器调用时,this指向他本身。
!(function () {
var myCla = function(){
this.name = 'sven';
};
var obj = new myCla();
console.log(obj.name); //sven
})()
但是,如果在方法中,进行闭包返回,那么结果就是最终返回的这个对象。
!(function () {
var myCla = function(){
this.name = 'sven';
return {
name : "an"
};
};
var obj = new myCla();
console.log(obj.name); //an
})()
构造函数
针对构造函数,简单说两点
使用new操作符被调用的函数,就只是一个普通函数。
实际上并不存在所谓的构造函数,只有对于函数的 构造调用。
使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
- 创建一个全新的对象。
- 这个对象会被执行 Prototype 链接。
- 这个对象会绑定到函数调用的this。
- 如果函数没有返回其他对象,那么new表达式中的函数调用会返回这个新对象。
4. 显示绑定:作为call或apply调用时,可以动态的改变传入函数this.
!(function () {
var obj1 = {
name:'sven',
getName:function(){
return this.name;
}
};
var obj2 = { name : "an"};
console.log(obj1.getName()); //sven
console.log(obj1.getName.call(obj2)); //an
})()
需要注意一点,就是对象变换。当你把对象引用到一个变量后,就会变成普通函数调用方法。
例如:var get = obj1.getName; get(); //undefind
使用Apply也可以做到借用其他对象的方法
!(function () {
var A = function (name) {
this.name = name;
};
var B = function(){
A.apply(this,arguments);
};
B.prototype.getName=function(){
return this.name;
};
var b = new B('save');
console.log(b.getName());
})()
硬绑定
this绑定中,存在this丢失情况。例如下面这种情景,this就会丢失。
!(function () { function foo() { console.log(this.a); } var obj = { a: 2, foo: foo }; var a = "window"; function consoleFoo(fn) { fn(); } consoleFoo(obj.foo); //undefined })()
这种时候,我们就可以使用硬绑定。
function bind(fn,obj){ return function(){ return fn.apply(obj,arguments); }; } var bar = bind(obj.foo,obj); consoleFoo(bar); //2
硬绑定在ES5中有自己独立的方法,我们可以直接调用。
var bar = obj.foo.bind(obj); consoleFoo(bar); //2
软绑定
软绑定会首先检查调用时的this,如果this绑定到全局对象或者undefined,那就把指定的默认对象obj绑定到this,否则不会修改this。
也就是如果当做普通方法调用,会进行绑定。如果当做对象函数隐示绑定,则不会修改。
!(function () { if(!Function.prototype.softBind){ Function.prototype.softBind = function(obj){ var fn = this; var curried = [].slice.call(arguments,1); var bound = function () { return fn.apply( (!this || this === (window || global)) ? obj:this, curried.concat.apply(curried,arguments) ); }; bound.prototype = Object.create(fn.prototype); return bound; } ; }; function foo() { console.log(this.name); } var obj = {name:"1"},obj1 = {name:"2"}; var fooObj = foo.softBind(obj); fooObj(); //1 obj1.foo = foo.softBind(obj); obj1.foo(); setTimeout(obj1.foo,10); //2 })()
执行顺序是:new -> 显示绑定 -> 隐示绑定 -> 普通方法
闭包
闭包两大知识点就是变量的作用域以及变量的生命周期
变量的作用域
作用域是指变量的有效范围。
在函数中声明变量的时候,该变量前面没有var,则变为全局变量,任何地方都可以访问到。
使用var关键字在函数内声明,即是局部变量。只要函数内部才能访问。函数外面是访问不到的。
var a = 1;
var func = function(){
var b =2;
var func2 = function(){
var c = 3;
console.log(a); //1
console.log(b); //2
};
console.log(c); //is not defined
};
变量的生命周期
对于全局变量来说,声明周期是永久的,除非主动销毁这个全局变量。
对于函数内的局部变量来说,当退出函数时就会销毁。
使用闭包的话会一直存在在匿名函数的引用中,则不会销毁。因为,v返回了一个匿名函数的引用,可以访问到func()方法里面,局部变量a一直处在这个环境里。所以能被外界访问。
!(function () {
var func = function(){
var a =1;
return function(){
a++;
console.log(a);
};
};
var v = func();
var b = func();
var c = v;
v(); //2
b(); //2
c(); //3
})()
绑定事件
因为javascript事件都是异步触发的,当事件被触发的时候,循环就结束了,所以i会保持循环最后的数值。可以添加立即执行函数,来进行执行。
var nodes = document.getElementsByTagName('div');
for (var i = 0; i < nodes.length; i++) {
(function (i) {
nodes[i].onclick = function () {
alert(i);
}
})(i)
}
闭包模式和模块模式
使用对象以方法的形式包含过程,闭包是在过程中以环境的形式包含数据。两个都可以达到一样的目的。
!(function () {
var extent = function(){
var value = 0;
return {
call:function(){
value++;
console.log(value);
}
};
};
var extent = extent();
extent.call();extent.call();extent.call();
//上为闭包写法,下为模块模式写法
function Module() {
var value = 0;
return {
call:function(){
value++;
console.log(value);
}
}
};
var extent2 = Module()
extent2.call();extent2.call();extent2.call();
})()
模块模式需要具备两个必要条件:
1. 必须有外部封装函数,该函数必须至少被调用一次(每次调用都会创建一个新的模块实例)
2.封闭函数必须返回至少一个内部函数,这样才能在私有作用域中形成闭包。并可以访问和修改私有状态。
我们可以对模块模式进行一下修改,变成单例模式:
var extent2 = (function Module() { var value = 0; return { call:function(){ value++; console.log(value); } } })();
面向委托设计
类理论
需要在软件中建模一些类似的任务。
如果使用类,设计方法可能是:定义一个基类,在基类中定义所有任务都有的行为。接着定义子类,他们都继承基类,添加特殊行为来处理对应任务。
类设计模式鼓励你在继承时使用方法重写,你会发现许多行为可先“抽象”到父类然后再有子类进行特殊化
构造完成后,只需要操作实例,每个实例都有你需要完成任务的所有行为。
委托理论
首先会定义一个Task对象,包含所有任务都可以使用的具体行为。对于任务会定义一个对象来存储对应的数据和行为。
会把特定的任务对象都关联到Task功能对象上,让它们需要的时候可以进行委托。
执行任务XYZ,需要XYZ和Task协作完成。但是我们不需要把这些行为放在一起,通过类的复制,我们可以把它们分别放在各自独立的对象中。
需要时可以允许XYZ对象委托给Task。下面是推荐的代码形式:
Task = { setID:function(ID){this.id = ID}, outputID:function(){console.log(this.id)} }; XYZ = Object.create(Task); XYZ.prepareTask = function(ID,Label) { this.setID(ID); this.label = Label; }
这段代码中,Task和XYZ不是类,它们是对象。XYZ通过Object.Create创建,它的Prototype委托了Task对象。
这种编程风格成为“对象关联”。关心的只是XYZ对象委托了Task对象。
对象关联风格代码有一些不同之处:
- id和label存储在XYZ上。通常prototype委托中最好把状态保存在委托者而不是委托目标上。
- 在委托行为中尽量避免在prototype链不同级别中使用相同的命名
- XYZ中的方法会首先找自身有没有setID,如果没有回在委托的Task中寻找。也就是XYZ进行交互时可以使用Task通用方法
这是一种强大的设计模式,和父类、子类、继承、多态等概念完全不同。是通过任意方向的委托关联并排组织的。
面向对象
function Foo(who){ this.me = who; } Foo.prototype.identify = function(){ return "I am "+this.me; } function Bar(who){ Foo.call(this,who); } Bar.prototype = Object.create(Foo.prototype); Bar.prototype.speak = function(){ console.log("Hello, "+this.identify() + "."); } var b1 = new Bar("b1"); var b2 = new Bar("b2"); b1.speak(); b2.speak();
对象关联
var Foo = { init: function (who) { this.me = who; }, identify: function () { return "I am " + this.me; } }; var Bar = Object.create(Foo); Bar.speak = function(){ console.log("Hello, "+this.identify()+"."); } var b1 = Object.create(Bar); b1.init("b1"); b1.speak();
使用对象关联可以让代码看起来更加简洁,还可以通过行为委托模式简化代码结构。
实际例子
我们看一个实际例子。创建UI控件按钮。
如果使用类设计模式,那么思路就是创建一个包含所有通过控件的基类,子类Button
function Widget(width,height){ //略 } Widget.prototype.render = function($css){ //略 } function Button(width,height,label){ Widget.call(this,width,height); //略 } Button.prototype = Object.create(Widget.prototype); Button.prototype.render = function($css){ //略 } var btn1 = new Button(12,12,12); btn1.render();
这个时候,我们重写的render只是添加一些按钮特有行为。这段代码中出现了伪多态,不是很好。
那么,我们可以使用委托编程。
var Widget = { init:function(width,height){ //略 }, insert:function($css){ //略 } }; var Button = Object.create(Widget); Button.setUp = function(width,height,label){
this.init(width,height);
//略 }; var btn1 = Object.create(Button); btn1.setUp(125,30,"Hello");
高级函数
currying(函数柯里化)
currying又称部分求值,当你传入函数的时候,不会立刻求值。会等到真正需要求值的时候,一次性求值。
//封装计算框架,其中算法使用参数传递
var currying = function (fn) {
var args = [];
return function () {
if (arguments.length === 0) {
return fn.apply(this, args);
} else {
[].push.apply(args, arguments);
return arguments.callee;
}
};
};
//定义实际算法
var cost = (function () {
var money = 0;
return function () {
for (var i = 0; i < arguments.length; i++) {
money += arguments[i];
}
return money;
};
})();
var cost = currying(cost);
cost(100);cost(100);cost(100);
console.log(cost());
函数节流
某些场合下,函数被非常频繁的调用,会造成巨大的性能影响。比如说,瀑布流,窗口大小等。
使用函数节流,可以按照我们需要的时间忽略掉一些请求。使用setTimeout方法。
//函数节流方法,第一个参数,执行函数。第二个参数,延迟时间
var throttle = function (fn, interval) {
var _self = fn, timer, firstTime; //定义函数引用,定时器,是否首次调用
return function () {
var args = arguments, _me = this;
if (firstTime) { //第一次调用不延迟
_self.apply(_me, args); //修正方法,传递参数
return firstTime = false; //不进行延迟
}
if (timer) { //判断计时器是否存在
return false; //存在代表尚在延迟时间内,忽略
}
timer = setTimeout(function () { //延迟执行一次
clearTimeout(timer); //取消方法
timer = null;
_self.apply(_me, args);
}, interval || 500);
};
};
window.onresize = throttle(function(){
console.log(1);
},500);
分时函数
页面渲染DOM时候,为了避免一次性加载过多的节点,添加的分时函数操作。
!(function () {
//分时函数.参数1,创建节点数据。2.封装节点逻辑,3,每一批节点数量
var timeChunk = function (ary, fn, count) {
var obj, t;
var len = ary.length;
var start = function () {
for (var i = 0; i < Math.min(count || 1, ary.length); i++) {
var obj = ary.shift(); //删除一个数
fn(obj);
}
};
return function () {
t = setInterval(function () {
if (ary.length === 0) {
return clearInterval(t);
}
start();
}, 200);
};
};
//实际调用方法
var ary = [];
for (var i = 1; i <= 1000; i++) {
ary.push(i);
}
var renderFirendList = timeChunk(ary, function (n) {
var div = document.createElement('div');
div.innerHTML = n;
document.body.appendChild(div);
}, 2);
renderFirendList();
})()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?