自学js第十一天:内置对象和方法

本文主要介绍了JavaScript中的内置对象及其方法,包括内置对象的分类、回调函数的概念与优势、以及Array和String对象的高阶方法如forEach、sort、map、filter、reduce等的使用和区别。此外,还探讨了Math对象和Date对象的部分方法。内容旨在帮助前端开发者更好地理解和运用JavaScript中的内置对象和方法。
摘要由CSDN通过智能技术生成

常用内置对象方法API

javascript内置对象都提供了基本方法, 学习方法需要注意 ①para参数 ②return返回值 ②是否改变原对象 三个点。

前端工作一定要经常看的:

MDN 官方文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects

一.首先先复习javascript中的对象分类.

JavaScript中的对象分为3种:
1.内置对象(内置大写包装类 , 常用功能类)
2.浏览器对象(DOM 和 BOM)、
3.自定义对象.

javascript是基于对象的语言, javascript不可以自己创建一个原生对象,只能访问内置对象属性和调用已有的内置对象方法。但是可以通过基于Object创建狭义概念上的对象

在这里插入图片描述

//JS的内置对象类,对象类内有各种各样的方法.
Number //数字
Boolean // 布尔
String //字符串
Object //对象,老祖宗类
Function //函数引用类型
Array  //数组
Date //时间
Math //数学
Null //空 
RegExp //正则表达式的对象

1.内置对象中的包装类

1.小写的基础类型undefined、null、boolean、number、string和symbol 都是非引用类型(非对象)

之前我们学习了对象 了解到 对象具有属性和方法 也学习了字面量值 我们一起来看一个案例

var str = '你好';
var arr = str.split('');
console.log(arr);
// ["你", "好"]
问题:

​一个以string基础类型的字面量为值的变量str 是如何能够通过 . 操作执行方法的呢? str到底是对象 还是 字符串呢?

var str = '你好';
//var newStr = new String('你好'); 包装 实例化对象
var arr = str.split('');
//var arr = newStr.split(''); 通过包装对象调用对象方法
// newStr = null; 销毁包装对象
console.log(arr);
// ["你", "好"]
几大包装类的具体案例:
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>instanceof</title>
</head>

<body>
  <script>

    
    var num =1;
    console.log(num instanceof Number); //false 
    //因为字面量num是基本类型number,而不是Number包装类对象,因此

    /*  
      var numObj = new Number(num);
       numObj.toString() 
       以上是js引擎帮我们自动num字面值转为包装类Number临时对象
       才可以让num去调用toString()方法,其实是包装类对象去numObj.toString()最后,才等于字面量 num.toString()
      */
    //numObj=null
    console.log(num.toString()); //'1' 
    //那为什么这里字面量却可以调用方法呢? 只有对象才能调用方法的吧?
    //原理:JS和java不同,js可以直接字面值变量去 . 调方法,
    //因为基本数据类型number在使用 点.调用 的时候js会帮我们自动生成一个Number包装类临时对象,
    //.调用用完会马上null自动销毁对象,如下.
    
      


    //相反如果字面量是一个真实的对象.则可以直接instanceof亲子鉴定对象类型.
    //想要是true,必须得是'对象'才可以用instanceof亲子鉴定比较.
    var numObj = new Number(1);
    console.log(numObj instanceof Number);  //true 
  

   


  
    
    //string基本类型案例:
    var str = 'N好啊';

    //下面是看不见隐式的生成,JS不会告诉你.
    // var strObj = new String('N好啊');
    // strObj.a = 'wob'; 
    //strObj.toLowerCase()
    str.a = 'wob';
  
    // strObj = null;  调用完临时对象,立马销毁,轮到当前的字面值去输出.
    console.log(str.a); //undefined  
    console.log(str.toLowerCase());  //n好啊 
  
   // 这里和上面Number一样,基础类型string的字面值在使用.的时候
    //其实JS自动是临时包装对象String类,然后其实是对象String的a属性,因此String内部没有a属性,
    //而自己不能自定义内置a属性,因此只能当成普通定义的var a;结果是undefined,
    //而.toLowerCase()方法是内置,String可以直接调用.
    


    //总结: 基本类型 VS 引用类型
    var str = 'fdsfsd'; //一个值    字面量值也不是一个对象 string基本类型的字面量

    var strO = new String('fdsfsd');//一个对象 一出生就有各种标准属性和方法

    //在 字面量值直接进行对应类型方法或者属性调用的时候 
    // 会套上一层包装对象来做 做完之后 包装对象销毁

    console.log(strO, str.toLocaleLowerCase()); // String "fdsfsd"

    // 对象 是否是 某个构造函数厂生产的
    console.log(str instanceof String); //false  (无包装过的)
    console.log(strO instanceof String); //true  (有包装过的)


   
  </script>
</body>

</html>
//规则如下:
//除了Object之外,其他包装类又有默认值,即new出来无参的时候是有默认值的.
//JS内obj 和 obj.toString没有任何关系了. java会是一样的输出引用等于调toString.
//obj.valueof是对象转为其内容字面值

//obj.toString是把对象具体内容转 为 字符串形式输出

//obj 是直接输出整个对象引用 即=右边的东西
// ①如果是对象字面值,则输出引用就和valueof一样是输出字面值内容 ,如下面第一个例子
//②如果是对象new实例化,则输出引用就是输出 = 右边的对象.如Number {1},就不是字面值了


<script>
     var object = {
    
      name : '小玲',
      age : 18,
      sex: false
    }
    console.log(object.valueOf() === object); //true
    console.log(object.valueOf()); //{name: "小玲", age: 18, sex: false}
    console.log(object); //{name: "小玲", age: 18, sex: false}
    console.log(object.toString()); //[object Object]  因为自定义类没有重写toStirng方法 

    
	var obj1 = new Object();
    console.log(obj1.valueOf() === obj1);//true
    console.log(1+obj1);//'1[object Object]'
    console.log(obj1.toString());//'[object Object]'
    console.log(obj1); //{}
    console.log(obj1.valueOf());//{}
  
    

    var obj = new Object(1); //自动转化为Number
    console.log(obj.valueOf() === obj);  //false
    console.log(obj.valueOf());//1
    console.log(1+obj);//2
    console.log(obj.toString());//'1'
    console.log(obj); //Number {1}
  
    
    var num1 = new Number();
    console.log( num1.valueOf() === num1);  // false
    console.log(1+num1);//1
    console.log(num1.valueOf());//0
    console.log(num1.toString());//'0'
    console.log(num1);//Number {0}


    var num = new Number(1);
    console.log( num.valueOf() === num); // false
    console.log(1+num);//2
    console.log(num.valueOf());//1
    console.log(num.toString());//'1'
    console.log(num);//test.html:49 Number {1}



    var str1 = new String();
    console.log( str1.valueOf() === str1); // false
    console.log(1+str1);//'11'
    console.log(str1.valueOf());//undefined
    console.log(str1.toString());//undefined
    console.log(str1);//String {""}

    var str = new String(true);
    console.log( str.valueOf() === str); // false
    console.log(1+str);//'11'
    console.log(str.valueOf());//;1'
    console.log(str.toString());//'1'
    console.log(str);//String {"true"}

    var bool1 = new Boolean();
    console.log( bool1.valueOf() === bool1); // false
    console.log(1+bool1);//1  因为flase转为0
    console.log(bool1.valueOf());//false
    console.log(bool1.toString());//'false'
    console.log(bool1);//Boolean {"flase"}

    var bool = new Boolean(-1); //''  0 NaN undefined  null 都会转为false,其他都是true
    console.log( bool.valueOf() === bool); // false
    console.log(1+bool);//2
    console.log(bool.valueOf());//隐式为true
    console.log(bool.toString());//'true'
    console.log(bool);//Boolean {"true"}

  </script>

二.CSDN什么回调函数:

1.先来看看什么是回调函数:下面的方法都和回调函数有关!!!

我们先来看看回调的英文定义:

A callback is a function that is passed as an argument to another function and is executed after its parent function has completed。

字面上的理解,回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。这个过程就叫做回调。
通俗其实也很好理解:回调,回调,就是回头调用的意思。主函数的事先干完,回头再调用传进来的那个函数。但是以前看过很多博客,他们总是将回调函数解释的云里雾里,很高深的样子。

举一个别人举过的例子:约会结束后你送你女朋友回家,离别时,你肯定会说:“到家了给我发条信息,我很担心你。” 对不,然后你女朋友回家以后还真给你发了条信息。小伙子,你有戏了。其实这就是一个回调的过程。你留了个参数函数(要求女朋友给你发条信息)给你女朋友,然后你女朋友回家,回家的动作是主函数。她必须先回到家以后,主函数执行完了,再执行传进去的函数,然后你就收到一条信息了。

现在基本理解回调函数的意思了吧。不理解的话没关系,我们用代码说话。

//异步,类似多线程,各走各的
//定义主函数,回调函数作为参数
function A(callback) {
   
    callback();   //后执行
    console.log('我是主函数'); //先执行     
}

//定义回调函数
function B(){
   
    setTimeout("console.log('我是回调函数')", 3000);//模仿耗时操作  ,该方法这里会导致异步
}

//调用主函数,将函数B传进去
A(B);

//输出结果
我是主函数
我是回调函数


//上面的代码中,我们先定义了主函数和回调函数,然后再去调用主函数,将回调函数传进去。
//定义主函数的时候,我们让代码先去执行callback()回调函数,但输出结果却是后输出回调函数的内容。这就说明了主函数不用等待回调函数执行完,可以接着执行自己的代码。所以一般回调函数都用在耗时操作上面。比如ajax请求,比如处理文件等。



//同步:排队等待
 //定义起始主函数,回调函数作为参数
function A(callback) {
    //登记电话号码
    callback();  //先
    console.log('我是主函数'); //后      
}

//定义回调函数
function B(){
     //电话号码
   console.log('我是回调函数')  
}

//调用起始的主函数,将回调函数B传进去,(类似foreach方法,传callback函数进去,便会唤醒回调函数事件,通俗讲就是传回调B函数,让起始函数的埋下的种子回调形参生效了)
A(B);//A去打电话号码B

//输出结果
// 我是回调函数
// 我是主函数

我能说这是在瞎扯吗,回调函数中的时间函数就是异步了,时间函数肯定是同步代码执行完后再执行,这跟回调函数有关系吗,你不用回调这个时间函数,主函数还是一样是是最后执行。 (这个是有道理的,看案例2同步排队时)

文章没说清楚,容易误导人。"主函数不用等待回调函数执行完,就可以接着执行自己的代码",这里是因为callback函数是异步的(即类似多线程各走各的),如果callback函数是同步的,则主函数还是要等待回调函数执行完,再执行自己的代码。

2.知乎回答的回调函数?

(1)我们绕点远路来回答这个问题。

编程分为两类:系统编程(system programming)和应用编程(application programming)。所谓系统编程,简单来说,就是编写;而应用编程就是利用写好的各种库来编写具某种功用的程序,也就是应用。系统程序员会给自己写的库留下一些接口,即API(application programming interface,应用编程接口),以供应用程序员使用。所以在抽象层的图示里,库位于应用的底下。

当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为B回调函数(callback function)。

打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把B回调函数传入类似内置好的foreach这样的库函数的动作,称为登记回调函数形参callback(to register a callback function)。如下图所示(图片来源:维基百科):

//上面这幅图就解释如下:main主函数先调用内置写好的foreach方法library库, 即主函数内的调用calls叫醒了foreach库函数,接着foreach内部再传入一个callback回调函数,此时就会立即唤醒已写好的回调函数的调用.(即 callback(arr[i], i, arr);这个写好的地方被唤醒) ,但是要先按顺序先执行foreach内部的代码先,然后才去调用回调函数, 即开始传实参并且调用,返回一些实参数据给function回调函数体形参那里,然后输出形参即可拿到实参数据.   

//这里是模拟一个写好的foreach库.
function forEach(arr, callback) {
   //形参,回调函数
      for (var i = 0, len = arr.length; i < len; i++) {
   
        callback(arr[i], i, arr); //调用回调函数
      }
    }

    forEach(['a', 'b', 'c', 'd', 'e'], function (current, index, array) {
    
      console.log(current, index, array);
    }) //实参
//可以看到,回调函数通常和应用处于同一抽象层(因为传入什么样的回调函数是在应用级别决定的)。而回调就成了一个高层调用底层,底层再回过头来调用高层的过程。(我认为)这应该是回调最早的应用之处,也是其得名如此的原因。
(2)回调机制的优势?

分解来讲就是:

1.回调function函数体{con}作为中间库函数例如map的实参 , 通过中间的库函数可被唤醒去调用回调 .
2.然后再从中间库函数中谋取一些数据来给调用回调函数充当局部实参,如果是全局变量则不用实参也可直接在回调函数内修改(即从中间库函数拿到需要调用,回调函数的实参数据,才能进入回调函数的调用), ,
3.最后调用回调函数callback();时,实参会对应回调回去给function回调函数体形参那里,然后输出形参即可拿到库函数内的一些实参数据.比如foreach遍历拿到数组每项元素/下标/整个数组
4.总结简单粗暴:回调函数体function(){con}就是一个中间接口,优点是可插拔,可以随意更换不同的回调函数体,然后去在js内置的库方法函数内的一些数据拿来当调用回调函数的实参.
因此: 传入不同功能的回调函数,回调回来结果表现也不同,这就是回调机制的优势所在
回调的例子:
监听VS绑定事件
       1.btnNext.onclick=unction showHa() {
    }绑定事件的showHa函数不是callback回调函数,
       只是事件的执行函数而已,即onclick这个事件会触发这个JS函数执行什么功能
       2.而btnNext.addEventListener('click', showHa);监听事件的showHa函数是一个callback回调函数,因为回调函数就是主函数套回函数,先主后回.主函数会从showHa回调函数那里谋取某些数据,来响应给click事件去执行输出
(3)从上面的例子可以看出,回调机制提供了非常大可插拔的灵活性。如下案例实现多个回调函数的可插拔.

请注意,从现在开始,我们把图中的库函数改称为中间函数了,这是因为回调并不仅仅用在应用和库之间。任何时候,只要想获得类似于上面情况的灵活性,都可以利用回调。

这种灵活性是怎么实现的呢?乍看起来,回调似乎只是函数间的调用,但仔细一琢磨,可以发现两者之间的一个关键的不同:在回调中,我们利用某种方式,把回调函数像参数一样传入中间函数。可以这么理解,在传入一个回调函数之前,中间函数是不完整的。换句话说,程序可以在运行时,通过登记不同的回调函数,来决定、改变中间函数的行为。这就比简单的函数调用要灵活太多了。请看下面这段Python写成的回调的简单示例:

#回调函数1
#生成一个2k形式的偶数,实现不同的功能的接口
def double(x):
    return x * 2
    
#回调函数2
#生成一个4k形式的偶数,实现不同的功能的接口
def quadruple(x):
    return x * 4

from even import *

#中间库函数,放回调函数形参和调用回调函数的地方
#接受一个生成偶数的函数作为参数
#返回一个奇数
def getOddNumber(k, getEvenNumber): //getEvenNumber是回调函数的形参 ,k是具体要计算的数值一起进去
    return 1 + getEvenNumber(k) //从中间库函数拿到需要数据,才进入回调函数的调用
// getEvenNumber(k)这里很精辟,中间库函数不仅只把callback预留形参,你甚至可以往中间库函数传的其他k参数,并把 其他参数拿来当回调函数调用的所要用到实参, 实现一箭双雕.
//反正回调函数的调用就是需要从中间库函数拿到数据当调用实参才能调用回调,
//当然回调函数的调用也可以不用实参,直接回去方法形参那里输出con语句即可也行,但一般都会放实参的,细品
    
#起始函数,这里是程序的主函数,即调用中间函数和放定义好的回调函数的地方
def main():    
    k = 1
    #当需要生成一个2k+1形式的奇数时
    i = getOddNumber(k, double)//插入回调函数实参
    print(i)
    #当需要一个4k+1形式的奇数时
    i = getOddNumber(k, quadruple)//插入回调函数实参
    print(i)
    #当需要一个8k+1形式的奇数时
    i = getOddNumber(k, lambda x: x * 8)
    print(i)
    
if __name__ == "__main__":
    main()
    
3
5
9    

上面的代码里,给getOddNumber传入不同的回调函数,它的表现也不同,这就是回调机制的优势所在。值得一提的是,上面的第三个回调函数是一个匿名函数。

(4)易被忽略的第三方

通过上面的论述可知,中间函数和回调函数是回调的两个必要部分,不过人们往往忽略了回调里的第三位要角,就是中间函数的调用者。绝大多数情况下,这个调用者可以和程序的主函数等同起来,但为了表示区别,我这里把它称为起始函数(如上面的代码中注释所示)。

之所以特意强调这个第三方,是因为我在网上读相关文章时得到一种印象,很多人把它简单地理解为两个个体之间的来回调用。譬如,很多中文网页在解释“回调”(callback)时,都会提到这么一句话:“If you call me, I will call you back.”我没有查到这句英文的出处。我个人揣测,很多人把起始函数和回调函数看作为一体,大概有两个原因:第一,可能是“回调”这一名字的误导;第二,给中间函数传入什么样的回调函数,是在起始函数里决定的。实际上,回调并不是“你我”两方的互动,而是ABC的三方联动。有了这个清楚的概念,在自己的代码里实现回调时才不容易混淆出错。

你到一个A商店买东西,刚好你要的东西没有货,于是你在A函数商店那里留下了你的电话名片(即callback函数形参),过了几天店里有货了,A商店调用自身,即主动打了你电话名片上的真正的电话号码(放入了B定义的回调函数体),
A店员要确定callback回调函数形参电话名片和B回调函数电话是对的上的, (callback形参要和A传来的B回调函数电话对的上,会即将是触发回调事件),然后你才会接到来电,你还让是A商店直接帮你买了货物,送到你家。(在A内,去可以调用回调函数,立即执行回调函数内部的程序,响应回调事件)

在这个例子里,你的电话号码就叫B回调函数,你把电话留给店员就叫callback登记回调函数,店里后来有货了给你打电话叫做触发了回调关联的事件,店内帮你买了货,叫做调用回调函数,取货送到你家叫做响应回调事件。回答完毕




 //同步:排队等待
 //定义起始主函数,回调函数作为参数
function A(callback) {
    //登记电话号码
    callback();  //先
    console.log('我是主函数'); //后      
}

//定义回调函数
function B(){
     //电话号码
   console.log('我是回调函数')  
}

//调用起始的主函数,将回调函数B传进去,(类似foreach方法,传callback函数进去,便会唤醒回调函数事件,通俗讲就是传回调B函数,让起始函数的埋下的种子回调形参生效了)
A(B);//A去打电话号码B

//输出结果
// 我是回调函数
// 我是主函数

3.百度回答什么是回调函数:

回调函数就是一个通过函数指针调用的函数。
将函数作为参数传递,并同时传递参数就可以实现回调函数。感觉和函数的特性有很大的关系,函数名称就是函数的一个指针,函数名加上()代表着执行这个指针对应的函数

如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,那就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

不管怎么说,回调函数是继承自C语言的。在C++中,应只在与C代码建立接口或与已有的回调接口打交道时,才使用回调函数。除了上述情况,在C++中应使用虚拟方法或仿函数(functor),而不是回调函数。

img

扩展资料

回调函数的好处:

1、回调函数可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。简而言之,回调函数就是允许用户把需要调用的函数的指针作为参数传递给一个函数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

2、回调可用于通知机制。例如,有时要在A程序中设置一个计时器,每到一定时间,A程序会得到相应的通知,但通知机制的实现者对A程序一无所知。那么,就需一个具有特定原型的函数指针进行回调,通知A程序事件已经发生。实际上,API使用一个回调函数SetTimer()来通知计时器。

参考资料来源:百度百科-回调函数




回调函数就是你写好一个函数,让预先写好的系统来调用。你去调用系统的函数,是直调。让系统调用你的函数,就是回调。但假如满足于这种一句话结论,是不会真正明白的。
回调函数可以看成,让别人做事,传进去的额外信息。
比如,A 让 B 做事,根据粒度不同,可以理解成 A 函数调用 B 函数,或者 A 类使用 B 类,或者 A 组件使用 B 组件等等。反正就是 A 叫 B 做事。
当 B 做这件事情的时候,自身的需要的信息不够,而 A 又有。就需要 A 从外面传进来,或者 B 做着做着主动向外面申请。对于 B 来说,一种被动得到信息,一种是主动去得到信息,有人给这两种方式术语,叫信息的 push,和信息的 pull。
A 调用 B,A 需要向 B 传参数。如简单的函数:
int max(int a, int b);
要使用这函数,得到两者最大的值, 外面就要传进来 a, b。这个很好理解。
void qsort(void *, size_t, size_t, int (*)(const void *, const void *));
而这个函数用于排序,最后一个参数就是回调函数,似乎就比较难以理解了。这是因为人为割裂了代码和数据。
我们暂停一下,看看计算机中比较诡异的地方,也就是代码(code)和数据(data)的统一。这是一个槛,如果不打通这个,很多概念就不清楚。我们常常说计算机程序分成 code 和 data 两部分。很多人就会觉得,code 是会运行的,是动的,data 是给 code 使用,是静态的,这是两种完全不同的东西。
其实 code 只是对行为的一种描述,比如有个机器人可以开灯,关灯,扫地。如果跟机器人约定好,0 表示开灯,1 表示关灯,2 表示扫地。我发出指令串,0 1 2,就可以控制机器人开灯,关灯,扫地。再约定用二进制表示,两位一个指令,就有一个数字串,000111,这个时候 000111 这串数字就描述了机器人的一系列动作,这个就是从一方面理解是 code,它可以控制机器人的行为。但另一方面,它可以传递,可以记录,可以修改,也就是数据。只要大家都协商好,code 就可以编码成 data, 将 data 解释运行的时候,也变成了 code。
code 和 data 可以不用区分,统一称为信息。既然 int max(int a, int b) 中 int,double 等表示普通 data 的东西可以传递进去,凭什么表示 code 的函数就不可以传进去了。有些语言确实是不区分的,它的 function(表示code)跟 int, double 的地位是一样的。这种语言就为函数是第一类值。
而有些语言是不能存储函数,不能动态创建函数,不能动态销毁函数。只能存储一个指向函数的指针,这种语言称为函数是第二类值。
另外有些语言不单可以传递函数,函数里面又用到一些外部信息(包括code, data)。那些语言可以将函数跟函数所用到的信息一起传递存储。这种将函数和它所用的信息作为一个整体,就为闭包。
将代码和数据打通,统一起来。过了这个槛,很多难以理解的概念就会清晰很多。
现在我们再回头看看回调函数。回调函数也就是是 A 让 B 做事,B 做着做着,信息不够,不知道怎么做了,就再让外面处理。
比如上述排序例子,A 让 B 排序,B 会做排序,但排序需要知道哪个比哪个大,这点 B 自己不知道,就需要 A 告诉它。而这种判断那个大,本身是一种动作,既然 C 语言中不可以传进第一值的函数,就设计成传递第二值的函数指针,这个函数指针就是 A 传向 B 的信息,用来表示一个行为。这里本来 A 调用 B 的,结果 B 又调用了 A 告诉它的信息,也就叫 callback。
再比如 A 让 B 监听系统的某个消息,比如敲了哪个键。跟着 B 监听到了,但它不知道怎么去处理这个消息,就给外面关心这个消息,又知道怎么去处理这个消息的人去处理,这个处理过程本身是个行为,既然这个语言不可以传递函数,又只能传一个函数指针了。假如我将函数指针存储下来,以后就可以随时调用。代码和数据都是信息,数据可以存储下来,用来表示行为的函数自然也可以存储下来。
跟着有些人有会引申成,什么注册啊,通知啊等等等。假如 B 做监听,C, D, E, F, G, H 告诉 B 自己有兴趣知道这消息,那 B 监听到了就去告诉 C,D,E,F,G等人了,这样通知多人了,就叫广播。
其实你理解了,根本不用去关心术语的。术语是别人要告诉你啊,或者你去告诉人啊,使用的一套约定的词语。本质上就这个东西,结果会有很多术语的。
跟着再将回调的概念泛化,比如某人同时关心 A, B, C, D, E, F 事件,并且这些事件是一组的,比如敲键盘,鼠标移动,鼠标点击等一组。将一组事件结合起来。在有些语言就映射成接口,接口有 N 个函数。有些语言就映射成一个结构,里面放着 N 个函数指针。跟着就不是将单个函数指针传进去,而是将接口,或者函数指针的结构传进去。根据不同的用途,有些人叫它为代理,监听者,观察者等等。
实际上也是将某种行为存储下来,以后有需要再进行调用。跟回调函数在更深层次是没有区别的。

4.简书的回调函数:

函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回;

回调函数

一个函数被作为参数传递给另一个函数(在这里我们把另一个函数叫做“otherFunction”),回调函数在otherFunction中被调用。

注意到click方法中是一个库函数而不是一个变量
//它就是回调函数
$("#btn_1").click(function() {
    //匿名fn是回调
    alert("Btn 1 Clicked");
});  
//或者

function click() {
    // 指针函数声明click,就是回调函数
    alert("Btn 1 Clicked");
}
$("#btn_1").click(click);  

回调函数是怎样运作的

因为函数在Javascript中是第一类对象,我们像对待对象一样对待函数,因此我们能像传递变量一样传递函数,在函数中返回函数,在其他函数中使用函数。当我们将一个回调函数作为参数传递给另一个函数是,我们仅仅传递了函数定义。我们并没有在参数中执行函数。我们并不传递像我们平时执行函数一样带有一对执行小括号()的函数。

需要注意的很重要的一点是回调函数并不会马上被执行。它会在包含它的函数内的某个特定时间点被“回调”(就像它的名字一样)

实现回调函数的基本原理

使用命名函数或者匿名函数作为回调

像之前的例子一样,第一种方法就是匿名函数作为回调(使用了参数位置定义的匿名函数作为回调函数)。第二种方式就是命名函数作为回调(定义一个命名函数并将函数名作为变量传递给函数)

传递参数给回调函数
//第一种方法:匿名函数作为回调函数
var generalLastName = "Cliton";
function getInput(options, callback){
   
    var arr = [];
    arr.push(options);
    //将全局变量generalLastName传递给回调函数
    callback(generalLastName,arr); //调用回调.
}
getInput({
   name:"Rich",speciality:"Javascript"}, function(generalLastName,arr){
   
    console.log(generalLastName + ":" + arr[0].speciality) // Cliton:Javascript
});

//第二种方法:命名函数作为回调函数
var generalLastName = "Cliton";
function getInput(options, callback){
   
    var arr = [];
    arr.push(options);
    //将全局变量generalLastName传递给回调函数
    callback(generalLastName,arr);
}
function call(generalLastName,arr){
    //单独定义一个call的回调函数
    console.log(generalLastName + ":" + arr[0].speciality) // Cliton:Javascript
}
getInput({
   name:"Rich",speciality:"Javascript"}, call);
在执行之前确保回调函数是一个函数
function getInput(options, callback){
   
    //确保callback是一个函数   
    if(typeof callback === "function"){
   
        //调用它,既然我们已经确定了它是可调用的
        callback(options);
    }
}
回调地狱(回调十八层地狱)
var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {
   }), {
   'pk':CustomPKFactory});
   p_client.open(function(err, p_client) {
   
       p_client.dropDatabase(function(err, done) {
   
           p_client.createCollection('test_custom_key', function(err, collection) {
   
               collection.insert({
   'a':1}, function(err, docs) {
   
                   collection.find({
   '_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) {
   
                       cursor.toArray(function(err, items) {
   
                           test.assertEquals(1, items.length);
                           // Let's close the db
                           p_client.close();
                       });
                   });
               });
           });
       });
   });
解决方案:
1.给你的函数命名并传递它们的名字作为回调函数,而不是主函数的参数中定义匿名函数。
2.模块化L将你的代码分隔到模块中,这样你就可以到处一块代码来完成特定的工作。然后你可以在你的巨型应用中导入模块。
创建你自己的回调函数
//callback,参数的最后一项,将会是我们在上面定义的genericPoemMaker函数
function getUserInput(firstName, lastName, gender, callback) {
   
    var fullName = firstName + " " + lastName;
    if (typeof callback === "function") {
   
        callback(fullName, gender);
    }
}  

function genericPoemMaker(name, gender) {
   
    console.log(name + " is finer than fine wine.");
    console.log("Altruistic and noble for the modern time.");
    console.log("Always admirably adorned with the latest style.");
    console.log("A " + gender + " of unfortunate tragedies who still manages a perpetual smile");
}

getUserInput("Michael", "Fassbender", "Man", genericPoemMaker); // 第一种方法:命名函数作为回调函数

getUserInput("Michael", "Fassbender", "Man", function(name, gender){
    // 第二种方法:匿名函数作为回调函数
    console.log(name + " is finer than fine wine.");
    console.log("Altruistic and noble for the modern time.");
    console.log("Always admirably adorned with the latest style.");
    console.log("A " + gender + " of unfortunate tragedies who still manages a perpetual smile");
});

4.脚本之家的回调函数:

回调函数,什么是回调函数呢?很多初学者都不是很明白,感觉懵懵的,不理解,更不会用!

其实简单理解的话就是在一个函数执行完毕后,得到想要的特定数据后再返回去去执行的函数,叫回调函数,并没有想想中的那么高深!


function getdata(callback){
   
    //这里我们假设是从后端获取数据
    setTimeout(function(){
   
     //假设我们获取到数据info
     var info = {
   
      "id":1,
      "name":'张三'
     }
     //得到数据以后执行函数方法
     callback(info)//这个就是回调函数
    },1000)
上述代码就可以清除的告诉你什么是回调函数!可能你还是不太明白,这个callback是什么,他有什么作用呢?


getdata(check)
   function getdata(callback){
   
    //这里我们假设是从后端获取数据
    setTimeout(function(){
   
     //假设我们获取到数据info
     var info = {
   
      "id":1,
      "name":'张三'
     }
     //得到数据以后执行函数方法
     callback(info)//这个就是回调函数
    },1000)
 }
function check(data){
   
  if(data.id==1){
   
   console.log('验证成功,可以通过')
  }
}
看上面的代码,有两个方法,getdata和check,我们执行了getdata方法,并把check当做参数传给了getdata,那么这时候check就是回调函数!

那么这个回调函数有什么作用呢,怎么用呢?如果你已经理解了回调函数的意义,那么你将很好的理解他的用法,记忆怎么在实际项目中去用他!

看下面的代码,我写的一种实际应用中的用法:


//vue框架的应用,其他框架的可以自行修改!!!
//用户权限验证实例:
created(){
   //在这个钩子函数中取执行获取数据的方法,将验证方法作为回调传入
  getdata(check)
 }
 methods:{
   //在这里面,首先你得有created钩子函数中用到的那两个方法
   function getdata(callback){
   //向后端请求用户信息
    //这里我们假设是从后端获取数据
    setTimeout(function(){
   
     //假设我们获取到数据info
     var info = {
   
      "id":1,
      "name":'张三'
     }
     //得到数据以后执行函数方法
     callback(info)//这个就是回调函数,得到用户信息后去验证他的权限
    },1000)
 }
function check(data){
   //验证用户权限
  if(data.id==1){
   //验证权限的条件,根据实际设定
   console.log('验证成功,可以通过')//权限通过,可以做什么
  }else{
   
   console.log('验证失败,禁止通行')//没有权限,可以做什么
  }
}
 }
总结

以上所述是小编给大家介绍的JS中回调函数及用法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
现在做native App  和Web App是主流,也就是说现在各种基于浏览器的web app框架也会越来越火爆了,做js的也越来越有前途。我也决定从后端开发渐渐向前端开发和手机端开发靠拢,废话不说了,我们来切入正题“js的回调函数”相关的东西。

      说起回调函数,好多人虽然知道意思,但是还是一知半解。至于怎么用,还是有点糊涂。网上的一些相关的也没有详细的说一下是怎么回事,说的比较片面。下面我只是说说个人的一点理解,大牛勿喷。我们来看一下一个粗略的一个定义“函数a有一个参数,这个参数是个函数b,当函数a执行完以后执行函数b。那么这个过程就叫回调。”,这句话的意思是函数b以一个参数的形式传入函数a并执行,顺序是先执行a ,然后执行参数b,b就是所谓的回调函数。我们先来看下面的例子。

复制代码代码如下:

   function  a(callback){
   
      alert('a');
      callback.call(this);//或者是 callback(),  callback.apply(this),看个人喜好
   }
   function  b(){
   
       alert('b');
   }
   //调用
   a(b);
       这样的结果是先弹出 'a',再弹出‘b'。这样估计会有人问了“写这样的代码有什么意思呢?好像没太大的作用呢!”

       是的,其实我也觉得这样写没啥意思,“如果调用一个函数就直接在函数里面调用它不就行了”。我这只是给大家写个小例子,做初步的理解。真正写代码的过程中很少用这样无参数的,因为在大部分场景中,我们要传递参数。来个带参数的:

复制代码代码如下:

function  c(callback){
   
      alert('c');
      callback.call(this,'d');
    }
//调用
c(function(e){
   
    alert(e);
});
      这个调用看起来是不是似曾相识,这里e参数被赋值为'd',我们只是简单的赋值为字符窜,其实也可以赋值为对象。Jquery里面是不是也有个e参数,下面我们就来讲讲
Jquery里面的e参数是如何被回调赋值的。

       Jquery框架我想大家不陌生了,出来了好久,开发的时候都在用,比较简单,api网上搜起来很方便,上手快。在Jquery框架下,我们有时候要获取事件中的一些参数,比如我要获取当前点击的坐标,点击的元素对象。这个需求在Jquery里面好办  :

复制代码代码如下:

        $("#id").bind('click',function(e){
   
          //e.pageX ,e.pageY ,e.target.....各种数据
        });
        用起来倒是挺方便,其实这个e参数的赋值也是通过回调函数来实现的,这个参数是用回调参数给它赋予了一个对象值,仔细研究过JJquery源码的朋友应该发现了这一点。

还有Ajax里面   $.get('',{
   },function(data){
   })    data这个参数也是同样的原理。

        我们来看看Jquery事件对象里面是怎么应用回调函数的。

       为了方便,我简单的写了一下$相关的一些实现,之前写过“小谈Jquery”里面有比较接近框架实现的方法,我下面只是写一个简易的选择器。

复制代码代码如下:

<div  id="container"   style="width:200px;height:200px;background-Color:green;">
</div>
<script>
     var   _$=function (id)
               {
   
                     this.element=  document.getElementById(id);
                }
       _$.prototype={
   
            bind:function(evt,callback)
            {
   
                var   that=this;
                if(document.addEventListener)
                {
   
                    this.element.addEventListener(evt, function(e){
   
                        callback.call(this,that.standadize(e));
                    }  ,false);
                }
                else if(document.attachEvent)
                {
   
                    this.element.attachEvent('on'+evt,function(e){
   
                        callback.call(this,that.standadize(e));
                    });
                }
                else
                    this.element['on'+evt]=function(e){
   
                        callback.call(this,that.standadize(e));
                    };
            },
            standadize:function(e){
   
                 var  evt=e||window.event;
                 var  pageX,pageY,layerX,layerY;
                 //pageX  横坐标  pageY纵坐标   layerX点击处位于元素的横坐标   layerY点击处位于元素的纵坐标
                 if(evt.pageX)
                 {
   
                     pageX=evt.pageX;
                     pageY=evt.pageY;
                 }
                 else
                 {
   
                    pageX=document.body.scrollLeft+evt.clientX-document.body.clientLeft;
                    pageY=document.body.scrollTop+evt.clientY-document.body.clientLTop;
                 }
                 if(evt.layerX)
                 {
   
                     layerX=evt.layerX;
                     layerY=evt.layerY;
                 }
                 else
                 {
   
                     layerX=evt.offsetX;
                     layerXY=evt.offsetY;
                 }
                 return  {
   
                    pageX:pageX,
                    pageY:pageY,
                    layerX:layerX,
                    layerY:layerY
                 }
            }
       }
       window.$=function(id)
       {
   
          return  new _$(id);
       }
        $('container').bind('click',function(e){
   
            alert(e.pageX);
        });
        $('container1').bind('click',function(e){
   
             alert(e.pageX);
        });
</script>
这段代码我们主要看standadize函数的实现,兼容性的代码,就不多说了,返回的是一个对象 

复制代码代码如下:

     return  {
   
                    pageX:pageX,
                    pageY:pageY,
                    layerX:layerX,
                    layerY:layerY
                 }
 然后再看bind函数里面的代码    callback.call(this,that.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值