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 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。

  1. 创建一个全新的对象。
  2. 这个对象会被执行 Prototype 链接。
  3. 这个对象会绑定到函数调用的this。
  4. 如果函数没有返回其他对象,那么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对象。

对象关联风格代码有一些不同之处:

  1. id和label存储在XYZ上。通常prototype委托中最好把状态保存在委托者而不是委托目标上。
  2. 在委托行为中尽量避免在prototype链不同级别中使用相同的命名
  3. 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();
})()
复制代码

 

posted @   Pino晨  阅读(311)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· 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,谁才是开发者新宠?
点击右上角即可分享
微信分享提示