1. 调音台的COMP是什么
调音台的第六排标有COMP的黄色旋钮是雅马哈调音台一个特有的功能旋钮。这个旋钮的功能是压限。作用是保护设备。一般情况下都是保持他在0db。
调音台(Mixer)又称调音控制台,它将多路输入信号进行放大、混合、分配、音质修饰和音响效果加工,之后再通过母线(Master)输出。调音台是现代电台广播、舞台扩音、音响节目制作等系统中进行播送和录制节目的重要设备。调音台按信号输出方式可分为模拟式调音台和数字式调音台。
调音台在输入通道数方面、面板功能键的数量方面以及输出指示等方面都存在差异,其实,掌握使用调音台,要总体上去考察它,通过实际操作和连接,自然熟能生巧。调音台分为三大部分:输入部分、母线部分、输出部分。母线部分把输入部分和输出部分联系起来,构成了整个调音台。
COMP基本原理
主要考虑同一区域天线端口之间的协作或不同区域中天线端口的协作; CoMP在一个eNodeB下设置多个射频模块接入点AP(Access Point),多个用户可以同时从同一个或不同的eNodeB中的一个或多个AP那里得到服务。
系统从分布的AP处收集信息,进行交互和计算后分配资源以满足用户的QoS需求和对整个网络资源的有效利用。
2. 如何理解c/c++和php语言的区别
一、编程语言
1.根据熟悉的语言,谈谈两种语言的区别?
主要浅谈下C/C++和PHP语言的区别:
1)PHP弱类型语言,一种脚本语言,对数据的类型不要求过多,较多的应用于Web应用开发,现在好多互联网开发公司的主流web后台开发语言,主要框架为mvc模型,如smarty,yaf,升级的PHP7速度较快,对服务器的压力要小很多,在新浪微博已经有应用,对比很明显。
2)C/C++开发语言,C语言更偏向硬件底层开发,C++语言是目前为止我认为语法内容最多的一种语言。C/C++在执行速度上要快很多,毕竟其他类型的语言大都是C开发的,更多应用于网络编程和嵌入式编程。
2.volatile是干啥用的,(必须将cpu的寄存器缓存机制回答得很透彻),使用实例有哪些?(重点)
1) 访问寄存器比访问内存单元要快,编译器会优化减少内存的读取,可能会读脏数据。声明变量为volatile,编译器不再对访问该变量的代码优化,仍然从内存读取,使访问稳定。
总结:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不再编译优化,以免出错。
2)使用实例如下( 区分C程序员和嵌入式系统程序员的最基本的问题。 ):
并行设备的硬件寄存器(如:状态寄存器)
一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
多线程应用中被几个任务共享的变量
3)一个参数既可以是const还可以是volatile吗?解释为什么。
可以。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。
4)一个指针可以是volatile 吗?解释为什么。
可以。尽管这并不是很常见。一个例子当中断服务子程序修改一个指向一个buffer的指针时。
下面的函数有什么错误:
int square(volatile int *ptr) {
return *ptr * *ptr;
}
下面是答案:
这段代码有点变态。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:
int square(volatile int *ptr){
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
由于*ptr的值可能被意想不到地改变,因此a和b可能是不同的。结果,这段代码可能并不是你所期望的平方值!正确的代码如下:
long square(volatile int *ptr){
int a;
a = *ptr;
return a * a;
}
更多linux内核视频教程文本资料免费获取后台私信【 内核 】。
3.static const等等的用法,(能说出越多越好)(重点)
² 首先说说const的用法(绝对不能说是常数)
1)在定义的时候必须进行初始化
2)指针可以是const 指针,也可以是指向const对象的指针
3)定义为const的形参,即在函数内部是不能被修改的
4)类的成员函数可以被声明为正常成员函数,不能修改类的成员变量
5)类的成员函数可以返回的是常对象,即被const声明的对象
6)类的成员变量是指成员变量不能在声明时初始化,必须在构造函数的列表里进行初始化
(注:千万不要说const是个常数,会被认为是外行人的!!!!哪怕说个只读也行)
下面的声明都是什么意思?
const int a; a是一个正常整型数
int const a; a是一个正常整型数
const int *a; a是一个指向常整型数的指针,整型数是不可修改的,但指针可以
int * const a; a为指向整型数的常指针,指针指向的整型数可以修改,但指针是不可修改的
int const * a const; a是一个指向常整型数的常指针,指针指向的整型数是不可修改的,同时指针也是不可修改的
通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
Const如何做到只读?
这些在编译期间完成,对于内置类型,如int, 编译器可能使用常数直接替换掉对此变量的引用。而对于结构体不一定。
² 再说说static的用法(三个明显的作用一定要答出来)
1)在函数体内,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
2)在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
3)在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用
4)类内的static成员变量属于整个类所拥有,不能在类内进行定义,只能在类的作用域内进行定义
5)类内的static成员函数属于整个类所拥有,不能包含this指针,只能调用static成员函数
static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
static全局变量与普通的全局变量有什么区别:static全局变量只初始化一次,防止在其他文件单元中被引用;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一次,下一次依据上一次结果值;
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
4.extern c 作用
告诉编译器该段代码以C语言进行编译。
5.指针和引用的区别
1)引用是直接访问,指针是间接访问。
2)引用是变量的别名,本身不单独分配自己的内存空间,而指针有自己的内存空间
3)引用绑定内存空间(必须赋初值),是一个变量别名不能更改绑定,可以改变对象的值。
总的来说:引用既具有指针的效率,又具有变量使用的方便性和直观性
6. 关于静态内存分配和动态内存分配的区别及过程
1) 静态内存分配是在编译时完成的,不占用CPU资源;动态分配内存运行时完成,分配与释放需要占用CPU资源;
2)静态内存分配是在栈上分配的,动态内存是堆上分配的;
3)动态内存分配需要指针或引用数据类型的支持,而静态内存分配不需要;
4)静态内存分配是按计划分配,在编译前确定内存块的大小,动态内存分配运行时按需分配。
5)静态分配内存是把内存的控制权交给了编译器,动态内存把内存的控制权交给了程序员;
6)静态分配内存的运行效率要比动态分配内存的效率要高,因为动态内存分配与释放需要额外的开销;动态内存管理水平严重依赖于程序员的水平,处理不当容易造成内存泄漏。
7. 头文件中的 ifndef/define/endif 干什么用 ?
预处理,防止头文件被重复使用,包括pragma once都是这样的
8. 宏定义求两个元素的最小值
#define MIN(A,B) ((A) next;
}
else
{
return NULL;
}
}
Node* pFind = pHead;
while (pCurrent) {
pFind = pFind->next;
pCurrent = pCurrent->next;
}
return pFind;
}
2. 给定一个单向链表(长度未知),请遍历一次就找到中间的指针,假设该链表存储在只读存储器,不能被修改
设置两个指针,一个每次移动两个位置,一个每次移动一个位置,当第一个指针到达尾节点时,第二个指针就达到了中间节点的位置
处理链表问题时,”快行指针“是一种很常见的技巧,快行指针指的是同时用两个指针来迭代访问链表,只不过其中一个比另一个超前一些。快指针往往先行几步,或与慢指针相差固定的步数。
node *create() {
node *p1, *p2, *head;
int cycle = 1, x;
head = (node*)malloc(sizeof(node));
p1 = head;
while (cycle)
{
cout > x;
if (x != 0)
{
p2 = (node*)malloc(sizeof(node));
p2->data = x;
p1->next = p2;
p1 = p2;
}
else
{
cycle = 0;
}
}
head = head->next;
p1->next = NULL;
return head;
}
void findmid(node* head) {
node *p1, *p2, *mid;
p1 = head;
p2 = head;
while (p1->next->next != NULL)
{
p1 = p1->next->next;
p2 = p2->next;
mid = p2;
}
}
3. 将一个数组生成二叉排序树
排序,选数组中间的一个元素作为根节点,左边的元素构造左子树,右边的节点构造有子树。
4. 查找数组中第k大的数字?
因为快排每次将数组划分为两组加一个枢纽元素,每一趟划分你只需要将k与枢纽元素的下标进行比较,如果比枢纽元素下标大就从右边的子数组中找,如果比枢纽元素下标小从左边的子数组中找,如果一样则就是枢纽元素,找到,如果需要从左边或者右边的子数组中再查找的话,只需要递归一边查找即可,无需像快排一样两边都需要递归,所以复杂度必然降低。
最差情况如下:假设快排每次都平均划分,但是都不在枢纽元素上找到第k大第一趟快排没找到,时间复杂度为O(n),第二趟也没找到,时间复杂度为O(n/2),第k趟找到,时间复杂度为O(n/2k),所以总的时间复杂度为O(n(1+1/2+....+1/2k))=O(n),明显比冒泡快,虽然递归深度是一样的,但是每一趟时间复杂度降低。
5. 红黑树的定义和解释?B树的基本性质?
红黑树:
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3. 每个叶子结点都带有两个空的黑色结点(被称为黑哨兵),如果一个结点n的只有一个左孩子,那么n的右孩子是一个黑哨兵;如果结点n只有一个右孩子,那么n的左孩子是一个黑哨兵。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
B树:
1.所有非叶子结点至多拥有两个儿子(Left和Right);
2.所有结点存储一个关键字;
3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树;
6. 常见的加密算法?
对称式加密就是加密和解密使用同一个密钥。
非对称式加密就是加密和解密所使用的不是同一个密钥,通常有两个密钥,称为“公钥”和“私钥”,它们两个必需配对使用。
DES:对称算法,数据加密标准,速度较快,适用于加密大量数据的场合;
MD5的典型应用是对一段Message产生fingerprint(指纹),以防止被“篡改”。
RSA是第一个既能用于数据加密也能用于数字签名的算法。
7. https?
HTTP下加入SSL层,HTTPS的安全基础是SSL。
8.有一个IP库,给你一个IP,如何能够快速的从中查找到对应的IP段?不用数据库如何实现?要求省空间
9.简述一致性hash算法。
1)首先求memcached服务器(节点)的哈希值,并将其配置到0 232的圆(continuum)。
2)然后采用同样的方法求出存储数据的键的哈希值,并映射到相同的圆上。
3)然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过232仍然找不到服务器,就会保存到第一台memcached服务器上。
11.描述一种hash table的实现方法
1) 除法散列法: p ,令 h(k ) = k mod p ,这里, p 如果选取的是比较大的素数,效果比较好。而且此法非常容易实现,因此是最常用的方法。最直观的一种,上图使用的就是这种散列法,公式: index = value % 16,求模数其实是通过一个除法运算得到的。
2) 平方散列法 :求index频繁的操作,而乘法的运算要比除法来得省时。公式: index = (value * value) >> 28 (右移,除以2^28。记法:左移变大,是乘。右移变小,是除)
3) 数字选择法:如果关键字的位数比较多,超过长整型范围而无法直接运算,可以选择其中数字分布比较均匀的若干位,所组成的新的值作为关键字或者直接作为函数值。
4) 斐波那契(Fibonacci)散列法:平方散列法的缺点是显而易见的,通过找到一个理想的乘数index = (value * 2654435769) >> 28
冲突处理:令数组元素个数为 S ,则当 h(k) 已经存储了元素的时候,依次探查 (h(k)+i) mod S , i=1,2,3…… ,直到找到空的存储单元为止(或者从头到尾扫描一圈仍未发现空单元,这就是哈希表已经满了,发生了错误。当然这是可以通过扩大数组范围避免的)。
12、各类树结构的实现和应用
13、hash,任何一个技术面试官必问(例如为什么一般hashtable的桶数会取一个素数?如何有效避免hash结果值的碰撞)
不选素数的话可能会造成hash出值的范围和原定义的不一致
14.什么是平衡二叉树?
左右子树都是平衡二叉树,而且左右子树的深度差值的约对值不大于1。
15.数组和链表的优缺点
数组,在内存上给出了连续的空间。链表,内存地址上可以是不连续的,每个链表的节点包括原来的内存和下一个节点的信息(单向的一个,双向链表的话,会有两个)。
数组优于链表的:
A. 内存空间占用的少。
B. 数组内的数据可随机访问,但链表不具备随机访问性。
C. 查找速度快
链表优于数组的:
A. 插入与删除的操作方便。
B. 内存地址的利用率方面链表好。
C. 方便内存地址扩展。
17.最小堆插入,删除编程实现
18. 4G的long型整数中找到一个最大的,如何做?
每次从磁盘上尽量多读一些数到内存区,然后处理完之后再读入一批。减少IO次数,自然能够提高效率。分批读入选取最大数,再对缓存的最大数进行快排。
19. 有千万个string在内存怎么高速查找,插入和删除?
对千万个string做hash,可以实现高速查找,找到了,插入和删除就很方便了。关键是如何做hash,对string做hash,要减少碰撞频率。
在内存中维护一个大小为10000的最小堆,每次从文件读一个数,与最小堆的堆顶元素比较,若比堆顶元素大,则替换掉堆顶元素,然后调整堆。最后剩下的堆内元素即为最大的1万个数,算法复杂度为O(NlogN)
(1)全局洗牌法
a)首先生成一个数组,大小为54,初始化为1~54
b)按照索引1到54,逐步对每一张索引牌进行洗牌,首先生成一个余数 value = rand %54,那么我们的索引牌就和这个余数牌进行交换处理
c)等多索引到54结束后,一副牌就洗好了
(2)局部洗牌法:索引牌从1开始,到54结束。这一次索引牌只和剩下还没有洗的牌进行交换, value = index + rand() %(54 - index)
算法复杂度是O(n)
22.请分别用递归和非递归方法,先序遍历二叉树
24.其他各种排序方法
25.哈希表冲突解决方法?
常见的hash算法如下:
解决冲突的方法:
也叫散列法,主要思想是当出现冲突的时候,以关键字的结果值作为key值输入,再进行处理,依次直到冲突解决
线性地址再散列法
当冲突发生时,找到一个空的单元或者全表
二次探测再散列
冲突发生时,在表的左右两侧做跳跃式的探测
伪随机探测再散列
同时构造不同的哈希函数
将同样的哈希地址构造成一个同义词的链表
建立一个基本表和溢出区,凡是和基本元素发生冲突都填入溢出区
六、系统架构
1.设计一个服务,提供递增的SessionID服务,要求保证服务的高可靠性,有哪些方案?集中式/非集中式/分布式
2.多台服务器要执行计划任务,但只有拿到锁的任务才能执行,有一个中心服务器来负责分配锁,但要保证服务的高可靠性。
3.如何有效的判断服务器是否存活?服务器是否踢出集群的决策如何产生?
4.两个服务器如何在同一时刻获取同一数据的时候保证只有一个服务器能访问到数据?
可以采用队列进行处理,写一个队列接口保证同一时间只有一个进程能够访问到数据,或者对于存取数据库的来说,数据库也是可以加锁处理的
5. 编写高效服务器程序,需要考虑的因素
性能对服务器程序来说是至关重要的了,毕竟每个客户都期望自己的请求能够快速的得到响应并处理。那么影响服务器性能的首要因素应该是:
(1)系统的硬件资源,比如说CPU个数,速度,内存大小等。不过由于硬件技术的飞速发展,现代服务器都不缺乏硬件资源。因此,需要考虑的主要问题是如何从“软环境”来提升服务器的性能。
服务器的”软环境“
(2)一方面是指系统的软件资源,比如操作系统允许用户打开的最大文件描述符数量
(3)另一方面指的就是服务器程序本身,即如何从编程的角度来确保服务器的性能。
主要就要考虑大量并发的处理这涉及到使用进程池或线程池实现高效的并发模式(半同步/半异步和领导者/追随者模式),以及高效的逻辑处理方式--有限状态机内存的规划使用比如使用内存池,以空间换时间,被事先创建好,避免动态分配,减少了服务器对内核的访问频率,数据的复制,服务器程序还应该避免不必要的数据复制,尤其是当数据复制发生在用户空间和内核空间之间时。如果内核可以直接处理从socket或者文件读入的数据,则应用程序就没必要将这些数据从内核缓冲区拷贝到应用程序缓冲区中。这里所谓的“直接处理”,是指应用程序不关心这些数据的具体内容是什么,不需要对它们作任何分析。比如说ftp服务器,当客户请求一个文件时,服务器只需要检测目标文件是否存在,以及是否有权限读取就可以了,不需要知道这个文件的具体内容,这样的话ftp服务器就不需要把目标文件读入应用程序缓冲区然后调用send函数来发送,而是直接使用“零拷贝”函数sendfile直接将其发送给客户端。另外,用户代码空间的数据赋值也应该尽可能的避免复制。当两个工作进程之间需要传递大量的数据时,我们就应该考虑使用共享内存来在他们直接直接共享这些数据,而不是使用管道或者消息队列来传递。上下文切换和锁:并发程序必须考虑上下文的切换问题,即进程切换或线程切换所导致的系统开销。即时I/O密集型服务器也不应该使用过多的工作线程(或工作进程),否则进程间切换将占用大量的CPU时间,服务器真正处理业务逻辑的CPU时间比重就下降了。因此为每个客户连接都创建一个工作线程是不可取的。应该使用某种高效的并发模式。(半同步半异步或者说领导者追随者模式)另一个问题就是共享资源的加锁保护。锁通常被认为是导致服务器效率低下的一个因素,因为由他引入的代码不仅不处理业务逻辑,而且需要访问内核资源,因此如果服务器有更好的解决方案,应该尽量避免使用锁。或者说服务器一定非要使用锁的话,尽量使用细粒度的锁,比如读写锁,当工作线程都只读一块内存区域时,读写锁不会增加系统开销,而只有当需要写时才真正需要锁住这块内存区域。对于高峰和低峰的伸缩处理,适度的缓存。
6. QQ飞车新用户注册时,如何判断新注册名字是否已存在?(数量级:几亿)
可以试下先将用户名通过编码方式转换,如转换64位整型。然后设置N个区间,每个区间为2^64/N的大小。对于新的用户名,先通过2分寻找该用户名属于哪个区间,然后在在这个区间,做一个hash。对于不同的时间复杂度和内存要求可以设置不同N的大小~
加一些基础的技术面试之外的职业素养的面试问题
1.你在工作中犯了个错误,有同事打你小报告,你如何处理?
a.同事之间应该培养和形成良好的同事关系,就是要互相支持而不是互相拆台,互相学习,互相帮助,共同进步。
b.如果小报告里边的事情都是事实也就是说确实是本人做的不好不对的方面,那么自己应该有则改之,提高自己。如果小报告里边的事
情全部不是事实,就是说确实诬陷,那么应该首先坚持日久见人心的态度,持之以恒的把本职工作做好,然后在必要的时候通过适当的
方式和领导沟通,相信领导会知道的。
2.你和同事合作完成一个任务,结果任务错过了截止日期,你如何处理?
3.职业规划?
4.离职原因?
5. 项目中遇到的难题,你是如何解决的?
A.时间 b要求 c.方法
3. 问个问题:上海的总面积大还是泉州的总面积大
上海简称沪。全市面积6340.5平方千米,占全国总面积的0.06%
泉州土地面积11015平方公里,现辖鲤城区、丰泽区、洛江区、晋江市、石狮市、南安市、惠安县、安溪县、永春县、德化县和金门县(待统一),以及肖厝区域。
泉州大
4. unity虚拟摇杆
在手机游戏中,虚拟摇杆游戏中的虚拟遥感很常见,先根据自己已经会虚拟摇杆来制作,虚拟摇杆醉主要的核心是
C#部分
2D虚拟摇杆
先弄个自定义的触发事件,然后给每一个需要触发的事件按钮添加,EventTrigget,需要注意的是这个事件要继承unity的接口,
制作unity的摇杆的话,需要继承unity的的UI接口 IBeginDragHandler, IDragHandler, IEndDragHandler,IPointerClickHandler
首先先定义四个委托
public Action<GameObject, PointerEventData> onBeginDrag;
public Action<GameObject, PointerEventData> onDrag;
public Action<GameObject, PointerEventData> onEndDrag;
public Action<GameObject, PointerEventData> onClick;
其次是重写unity继承的四个接口,把每个委托的回调放进去这些接口函数里面,一但满足条件,委托会执行函数回调方法
public void OnBeginDrag(PointerEventData eventData) {
if (onBeginDrag != null)
{
onBeginDrag(gameObject, eventData);
}
}
public void OnDrag(PointerEventData eventData) {
if (onDrag != null)
{
onDrag(gameObject, eventData);
}
}
public void OnEndDrag(PointerEventData eventData) {
if (onEndDrag != null)
{
onEndDrag(gameObject, eventData);
}
}
public void OnPointerClick(PointerEventData eventData){
if (onClick != null)
{
onClick(gameObject, eventData);
}
}
有了这些委托方法之后,如何使用,这个调用方法,会在初始化注册事件,
public static EventTrigger GetEventCallBack(GameObject obj)
{
Event trigger = obj.GetComponent<EventTrigger>();
if (trigger == null)
{
trigger = obj.AddComponent<EventTrigger>();
}
return trigger;
}
创建以一个控制虚拟摇杆StickJoyUI脚本,注册委托事件
TriggerEvent.Get(bgObj).onBeginDrag = OnDragBegin;
TriggerEvent.Get(bgObj).onDrag = OnDrag;
TriggerEvent.Get(bgObj).onEndDrag = OnDragEnd;
TriggerEvent.Get(transform.Find("changeAttack").gameObject).onClick = OnChangeAttack;
TriggerEvent.Get(transform.Find("AttackBtn").gameObject).onClick = OnAttackBtn;
再来看看虚拟摇杆部分OnDragBegin OnDrag OnDragEnd 这个三个方法控制虚拟摇杆,
private void OnDragBegin(GameObject obj, PointerEventData evetData)
{
}
private void OnDrag(GameObject obj, PointerEventData evetData)
{ Vector2 point;
//("需要转换的对象的父级的RectTrasform","鼠标的位置","当前的摄像机","转换后的ui的相对坐标")
bg为要拖拽的对象的父级对象,里面还有一个小圆PointTf,鼠标的位置取拖拽事件的的position,鼠标的位置取拖拽事件的的摄像机,转
if (RectTransformUtility.(bgTf, evetData.position, evetData.pressEventCamera, out point)) {
//拖动的方向
Vector2 v = (point - Vector2.zero).normalized;
x = v.x;
y = v.y;
if (Vector2.Distance(point, Vector2.zero) <= R)
{
pointTf.anchoredPosition = point;
}
else //超出移动的半径
{
//位置 = 初始位置 + 方向 * 距离
pointTf.anchoredPosition = Vector2.zero + v * R;
}
}
}
private void OnDragEnd(GameObject obj, PointerEventData evetData)
{
pointTf.anchoredPosition = Vector2.zero;
x = 0;
y = 0;
}
Ps:2D角色还需要注意人物朝向问题
只需要把里面的的X值和Y值赋予给他实时更新,然后在写一个Flip方法判断朝向问题,本质是修改一下缩放的X改成相反的值就好了
//朝向
void Flip()
{
if (x > 0)
{
transform.localScale = new Vector3(1, 1, 1);
}
else if (x < 0)
{
transform.localScale = new Vector3(-1, 1, 1);
}
}
3D模式:把把X值和Y赋予个移动函数的x值和z值即可
接下用js实现虚拟摇杆(思路跟上面差不多,但是数据的处理稍有差别而已)
首先引入玩家模块
var Player = require("player");
属性定义
cc.Class({
extends: cc.Component,
properties: {
stickNode:{
default:null,
type:cc.Node
},
fillNode:{
default:null,
type:cc.Node
},
skillBtn:{
default:null,
type:cc.Node
},
player:{
default:null,
type:Player
},
R:50,
stick_x:0,
stick_y:0
},
在初始化函数Onlade中注册事件
onLoad () {
this.stickNode = cc.find("Stick",this.node);
this.fillNode = cc.find("Stick/fill",this.node);
this.skillBtn = cc.find("skillBtn",this.node);
//注册开始拖拽,拖拽事件,拖拽结束事件,和点击事件,这个更上面的四个接口类似
this.stickNode.on(cc.Node.EventType.TOUCH_START,this.onTouchStart,this);
this.stickNode.on(cc.Node.EventType.TOUCH_MOVE,this.onTouchMove,this);
this.stickNode.on(cc.Node.EventType.TOUCH_END,this.onTouchEnd,this);
this.stickNode.on(cc.Node.EventType.TOUCH_CANCEL,this.onTouchCancel,this);
this.skillBtn.on("click",this.onClickSkillBtn,this);
},
onTouchStart(event)
{
},
onTouchMove(event)
{
var pos = event.getLocation();//v2类型 坐标系
//当前这个鼠标的世界坐标转换成当前节点的相对坐标
pos = this.stickNode.convertToNodeSpaceAR(pos);
if(pos.magSqr()<=this.R*this.R)
{
this.fillNode.setPosition(pos);
}
else
{
this.fillNode.x = pos.normalizeSelf().x*this.R;
this.fillNode.y = pos.normalizeSelf().y*this.R;
}
this.stick_x = pos.normalizeSelf().x;
this.stick_y = pos.normalizeSelf().y;
},
onTouchEnd(event)
{
this.fillNode.x = 0;
this.fillNode.y = 0;
this.stick_x = 0;
this.stick_y = 0;
},
onTouchCancel(event)
{
this.fillNode.x = 0;
this.fillNode.y = 0;
this.stick_x = 0;
this.stick_y = 0;
},
onClickSkillBtn()
{
//执行玩家脚本使用技能的方法
this.player.playSkill();
}
PS:计算上面的pos的方向, 上面为啥半径平方而不是把开方呢??,开方消耗性能,给半径平方两者比较也能比较,相对与前者开方,后者半径平方更加节省性能,采用迂回思路,感觉这种思想有很多地方都用到,就比如前面的浮点数处理,既然有误差,那么我可以放大倍数,然后要使用时候,我再缩小倍数。
5. 基带和频带的区别
通常大型建筑物内部的层间有楼板,房间有墙壁,室内与室内用户之间有空间分割,BBU+RRU多通道方案就是利用这一特性。对于超过10万平方米的大型体育场馆,可将看台划分为几个小区,每个小区设置几个通道,每个通道对应一面板状天线。
通常室内分布系统采用电缆的电分布方式,而BBU+RRU方案则采用光纤传输的分布方式。基带BBU集中放置在机房,RRU可安装至楼层,BBU与RRU之间采用光纤传输,RRU再通过同轴电缆及功分器(耦合器)等连接至天线,即主干采用光纤,支路采用同轴电缆。
对于下行方向:光纤从BBU直接连到RRU,BBU和RRU之间传输的是基带数字信号,这样基站可以控制某个用户的信号从指定的RRU通道发射出去,这样可以大大降低对本小区其他通道上用户的干扰。
对于上行方向:用户手机信号被距离最近的通道收到,然后从这个通道经过光纤传到基站,这样也可以大大降低不同通道上用户之间的干扰。BBU+RRU方案对于容量配置非常灵活,可按容量需求,在不改变RRU和室内分布系统的前提下,通过配置BBU来支持每通道从1/6载波到3载波的扩容。
全称Building Base band Unit ,中文名:基带处理单元。RRU(射频拉远单元)和BBU(基带处理单元)之间需要用光纤连接。一个BBU可以支持多个RRU。采用BBU+RRU多通道方案,可以很好地解决大型场馆的室内覆盖。
基带传输
在信道中直接传送基带信号时,称为基带传输。进行基带传输的系统称为基带传输系统。传输介质的整个信道被一个基带信号占用.基带传输不需要调制解调器,设备花费小,具有速率高和误码率低等优点,适合短距离的数据传输,传输距离在100米内,在音频市话、计算机网络通信中被广泛采用。
在有线信道中,直接用电传打字机进行通信时传输的信号就是基带信号。一个企业、工厂,就可以采用这种方式将大量终端连接到主计算机。基带数据传输速率为0~10Mb/s,更典型的是1Mb/s~2.5Mb/s,通常用于传输数字信息。
频带传输
在信道中直接传送频带信号时,称为频带传输。可以远距离传输.它的缺点是速率低,误码率高.
一般说的频带传输是数字基带信号经调制变换,成为能在公用电话线上传输的模拟信号,模拟信号经模拟传输媒体传送到接收端后,再还原成原来信号的传输。这种频带传输不仅克服了许多长途电话线路不能直接传输基带信号的缺点,而且能够实现多路复用,从而提高了通信线路的利用率。但是频带传输在发送端和接收端都要设置调制解调器,将基带信号变换为频带信号再传输。频带传输的优点是可以利于现有的大量模拟信道(如模拟电话交换网)通信.价格便宜,容易实现.家庭用户拨号上网就属于这一类通信.
宽带传输
宽带传输Broadband,是相对一般说的频带传输而言的宽频带传输。宽带是指比音频带宽更宽的频带,它包括大部分电磁波频谱。使用这种宽频带传输的系统,称为宽带传输系统.其通过借助频带传输,可以将链路容量分解成两个或更多的信道,每个信道可以携带不同的信号,这就是宽带传输。宽带传输中的所有信道都可以同时发送信号。如CATV、ISDN等。传输的频带很宽在>=128kbps
宽带是传输模拟信号,数据传输速率范围为0~400Mb/s,而通常使用的传输速率是5Mb/s~10Mb/s。它可以容纳全部广播,并可进行高速数据传输。宽带传输系统多是模拟信号传输系统。
一般说,宽带传输与基带传输相比有以下优点:
(1)能在一个信道中传输声音、图像和数据信息,使系统具有多种用途;
(2)一条宽带信道能划分为多条逻辑基带信道,实现多路复用,因此信道的容量大大增加;
(3)宽带传输的距离比基带远,因数字基带直接传送数字,传输的速率愈高,传输的距离愈短。
不要混淆基带,基带信号,基带传输这几个概念。
通常情况下,(Radio Remote Unit)) ,是在远端将基带光信号转成射频信号放大传送出去。直放站就是将基站射频信号接收放大再传送出去。区别就是直放站会将噪声同时放大,而射频拉远则不会。
RRU基本介绍
拉远就是把基站的基带单元和射频单元分离,两者之间传输的是基带信号,而光纤直放站是从基站的射频输出口耦合出射频信号转换为光信号在光纤中传输,然后远端再转为射频放大!
RRU工作原理
射频拉远单元RRU(Radio Remote Unit)带来了一种新型的分布式网络覆盖模式,它将大容量宏蜂窝基站集中放置在可获得的中心机房内,基带部分集中处理,采用光纤将基站中的射频模块拉到远端射频单元,分置于网络规划所确定的站点上,从而节省了常规解决方案所需要的大量机房;同时通过采用大容量宏基站支持大量的光纤拉远,可实现容量与覆盖之间的转化。
RRU的工作原理是:基带信号下行经变频、滤波,经过射频滤波、经线性功率放大器后通过发送滤波传至天馈。上行将收到的移动终端上行信号进滤波、低噪声放大、进一步的射频小信号放大滤波和下变频,然后完成模数转换和数字中频处理等。
RRU同基站接口的连接接口有两种:CPRI(Common Public Radio Interface 通用公共射频接口)及OBSAI(Open Base Station Architecture Initiative 开放式基站架构)。
信号覆盖方式上,RRU可通过同频不同扰码方式,从NodeB引出。也可通过同频不同扰码方式,从RNC引出。这两种覆盖方式都是常规的方式,除此之外,对于3扇区,但配有多余信道板以及多余基带处理设备的基站可以利用基带池共享技术,将多余的基带处理设备设为第4小区
RRU同数字光纤直放站都可利用现有成熟的以太网数字光纤传输技术传输基带信号,并共同遵守标准的CPRI和OBSAI接口。使用中可实现RRU和数字光纤直放站的远端机的互相替换。
两者均可作为室内分布系统的信号源,选用哪一种取决于宏基站的载频数量和该室内业务量需求。如果宏基站载频多、容量很富裕,用数字光纤直放站拉远更合适,同时可减少扇区扰码。如果该室内业务量需求较大应选用RRU作信号源。如果业务量需求很大,如大型写字楼、会展中心等,应考虑数字光纤直放站、RRU和宏基站的联合组网。
在覆盖距离上,两者均可作为基站拉远系统供用,数字光纤直放站用作载波池拉远,RRU可用作基带池拉远。载波池拉远距离取决于小区覆盖半径和光在光纤上的传输速度,数字信号在光纤中传播,其动态范围也较模拟信号大,这样就可以实现远端机更大的信号覆盖;同时,数字信号不随光信号的衰减而衰减,因此其传输(拉远)距离也进一步增加了。经计算,最远可达40km以上,用作基带池拉远的RRU基本不受距离限制,可拉得更远。
在组网方式上,RRU作为拉远单元可单独使用,而数字光纤直放站由近端机和远端机组成,在实际应用时,近端机是一个,而远端机可以是一个或多个,组网上可并联也可串联,组网方式也可以多样化,如:菊花链形、环形、树形等等。
在扰码的使用上,数字光纤直放站射频信号的扰码总是同施主基站的扰码相同,数字光纤直放站也不增加基站信道板硬件容量和正交码容量,所以在扇区内大量采用并不会增加扰码。射频拉远单元RRU是利用基站剩余的信道板和基带处理设备组成新的扇区,通过光纤系统拉到远处,有人称它为基带池技术,也有人叫它拉远的微蜂窝技术,总之,它具有硬件容量,并且拥有新的扰码和同步码。由于RRU具有基站性能,在宏基站的扇区内大量采用必然会增加很多扰码和邻区列表,会发生导频污染,软切换增加。在网络优化时这是必须注意的问题。
在传输时延上,数字光纤直放站的传输时延比较大,因为存在两次变频过程。而RRU直接传送基带信号,时延不明显。
在底噪抬升上,数字光纤直放站仅采用ADC和DAC,此过程只可能引入更多的量化噪声,从而抬升上行噪声。而RRU传输的为纯基带信号,可不用考虑底噪问题。
从成本上,采用RRU技术,可以节省常规建网方式中需要的大量机房,节约基带单元的投资。RRU体积小,重量轻,可以应用于城区机房条件不理想或者机房匮乏的情况,但是应用前提是需要有光纤进行传输。但在价格方面,RRU比直放站要贵1/3左右。对于一拖一的系统,数字光纤直放站成本优势不明显,但一拖多,成本优势就比较明显了。
6. 西班牙的英语
您想问西班牙用英语怎么说。西班牙的英语单词为Spain。
西班牙语言languagesofspain,Spanishlanguages。西班牙语语法Spanishgrammar,GrammaroftheSpanishlanguage。西班牙语动词spanishconjugation。
西班牙(Espa_a)全称西班牙王国(西班牙语:ReinodeEspa_a,英语:TheKingdomofSpain),是一个位于欧洲西南部的君主立宪制国家。地处欧洲与非洲的交界,西邻同处于伊比利亚半岛的葡萄牙,北濒比斯开湾,东北部与法国及安道尔接壤,南隔直布罗陀海峡与非洲的摩洛哥相望,领土还包括地中海中的巴利阿里群岛,大西洋的加那利群岛及非洲的休达和梅利利亚。该国是一个多山国家,总面积505925平方公里,其海岸线长约7800公里。
7. 广州市天河区的面积到底是多少
天河区位于中国第三大城市广州市老城区的东部,东到玉树尖峰岭、吉山狮山、前进深涌一带,与黄埔区相连;南到珠江,与海珠区隔江相望;西从广州大道、杨箕、先烈东路、永福路,沿广深铁路方向达登峰,与越秀区相接;北到筲箕窝,与白云区和萝岗区相接,总面积96.33平方千米。
8. nodejs + express怎么实现Ajax方式及其简单功能
nodejs + express怎么实现Ajax方式及其简单功能
4) 对库函数的调用不需要再作说明,但必须把该函数的头文件用include命令包含在源文件前部。
8.5 函数的嵌套调用
C语言中不允许作嵌套的函数定义。因此各函数之间是平行的,不存在上一级函数和下一级函数的问题。但是C语言允许在一个函数的定义中出现对另一个函数的调用。这样就出现了函数的嵌套调用。即在被调函数中又调用其它函数。这与其它语言的子程序嵌套的情形是类似的。其关系可表示如图。
图表示了两层嵌套的情形。其执行过程是:执行main函数中调用a函数的语句时,即转去执行a函数,在a函数中调用b 函数时,又转去执行b函数,b函数执行完毕返回a函数的断点继续执行,a函数执行完毕返回main函数的断点继续执行。
【例8.4】计算s=22!+32!
本题可编写两个函数,一个是用来计算平方值的函数f1,另一个是用来计算阶乘值的函数f2。主函数先调f1计算出平方值,再在f1中以平方值为实参,调用 f2计算其阶乘值,然后返回f1,再返回主函数,在循环程序中计算累加和。
long f1(int p)
{
int k;
long r;
long f2(int);
k=p*p;
r=f2(k);
return r;
}
long f2(int q)
{
long c=1;
int i;
for(i=1;i<=q;i++)
c=c*i;
return c;
}
main()
{
int i;
long s=0;
for(i=2;i<=3;i++)
s=s+f1(i);
printf("\ns=%ld\n",s);
}
9. 用C语言编写一个计算器程序,实现加,减,乘,除,求平方根(正数),倒数等功能.
#include<iostream>
#include<cmath>
#include<string>
using namespace std;
const double pi = 3.14159265; const double e = 2.718281828459; const int SIZE = 1000;
typedef struct node//为了处理符号而建立的链表(如: 1+(-2)) { char data; node *next; }node;
typedef struct stack_num//存储 数 的栈 { double *top; double *base; }stack_num;
typedef struct stack_char//存储 运算符号 的栈 { char *top; char *base; }stack_char;
stack_num S_num;//定义 stack_char S_char;//定义
char fu[18] = {'\n', ')', '+', '-', '*', '/', '%', '^', 'Q', 'L', 'C', 'S', 'T', 'c', 's', 't', '('};
int compare[1000];//表现出各运算符号的优先级 double shu[1000];//存储 "数" 的数组
double dai_result;//运算的结果,是为了处理 M 运算(简介函数里有M的定义) int biao = 0;//和dia_result 一样,为了处理 M 运算 char line[SIZE];//输入的所要计算的表达式
void init()//初始化 { compare[fu[0]] = -2;//用数字的大小表现出符号的优先级
compare[fu[1]] = -1; compare[fu[2]] = 2; compare[fu[3]] = 2; compare[fu[4]] = 4; compare[fu[5]] = 4; compare[fu[6]] = 4; compare[fu[7]] = 5; for(int i = 8; i <= 15; i++) compare[fu[i]] = 6; compare[fu[16]] = 7; S_num.base = (double*)malloc(sizeof(double)*SIZE);//为栈开辟空间 S_char.base = (char*)malloc(sizeof(char)*SIZE);//同上 S_num.top = S_num.base; S_char.top = S_char.base; }
void push_num(double n)//数字进栈 { * ++S_num.top = n; }
void push_char(char c)//运算符号进栈 { * ++S_char.top = c; }
double pop_num()//数字出栈 { double m = *S_num.top; S_num.top--; return m; }
char pop_char()//运算符号出栈 { char cc = *S_char.top; S_char.top--; return cc; }
char get_top_char()//得到运算符号的栈中最顶端的运算符号 { return *S_char.top;
}
double operate(double y, char c, double x)//
对两个数计算
(
含是双目运算符
:
如
*, /
等等
)
{
double r;
if(c == '-')
r = x - y;
else if(c == '+')
r = x + y;
else if(c == '/' && y != 0)
r = x / y;
else if(c == '*')
r = x * y;
else if(c == '^')
{
r = 1;
for(int i = 1; i <= y; i++)
r *= x;
}
else if(c == '%')
{
int r0 = (int)x % (int)y;
r = double(r0);
}
return r;
}
double operate_one(double one, char cc)//
对一个数运算
(
含单目运算符
:
如
log(L), sin(S)
等等
)
{
double r;
if(cc == 'Q')
r = sqrt(one);
else if(cc == 'C')
r = cos(one);
else if(cc == 'S')
r = sin(one);
else if(cc == 'T')
r = tan(one);
else if(cc == 'c')
i++;
}
i++;
}
if(ge >= 3)
return 0;
else
return 1;
}
void output(double result)//
打出结果
{
printf("
所得结果是
: ");
cout<<result<<endl;
}
void check()//
检查表达式是否合法
{
void introce();
char cc;//
决定计算器按哪种功能进行计算
double result;//
结果
void input();//
定义
if( check_kuohao() && check_char() )//
看是否合法
,
合法则计算
{
result = compute();
output(result);
cout<<"
输入一个字符
'M'
或
'D'
或
'F',
决定是否继续
: "<<endl;
while(cin>>cc)
{
if(cc == 'M')
{
system("cls");
introce();
printf("
您上次所得结果为
: ");
cout<<result<<endl;
cout<<"
在上次计算结果的基础上
,
请继续输入想计算的表达式
"<<endl;
dai_result = result;
biao = 1;
input();//
输入表达式
break;
}
else if(cc == 'D')
{
system("cls");
introce();
cout<<"
计算器已清零
,
请输入您所要计算的表达式
"<<endl;
input();//
输入表达式
break;
}
else if(cc == 'F')
{
system("cls");
cout<<"
计算器关闭
,
谢谢使用
!"<<endl;
break;
}
else
{
cout<<"
所输入字符无效
,
请输入一个字符
'M'
或
'D'
或
'F'!"<<endl;
continue;
}
}
}
else//
不合法,分两种不合法
{
if(check_kuohao() == 0 && check_char() == 1)
{
cout<<"
您所输入的表达式括号不匹配
,
请重新输入
:"<<endl;
input();//
输入表达式
}
else
{
cout<<"
您所输入的表达式不合法
,
请重新输入
:"<<endl;
input();//
输入表达式
}
}
}
void tackle_fuhao()//
处理负号
{
node *root, *head, *p, *q, *p1;
root = head = new node;
head->next = NULL;
int i;
for(i = 0; line[i] != '\0'; i++)//
建立链表
{
p = new node;
p->data = line[i];
p->next = head->next;
head->next = p;
head = p;
}
// delete p;
q = (node*)malloc(sizeof(node));
head = root;
if(root->next->data == '+' || root->next->data == '-')//
处理第一个字符
{
p = new node;
p->data = '0';
p->next = head->next;
head->next = p;
}
if(root->next != NULL)
{
for(q = root->next; q; q = q->next)
{
if(q->data == '(' && (q->next->data == '-' || q->next->data == '+'))
{
p = new node;
p->data = '0';
p->next = q->next;
q->next = p;
}
}
}
// delete q;
p1 = new node;
int qi = -1;
for(p1 = root->next; p1; p1 = p1->next)
{
line[++qi] = p1->data;
}
line[++qi] = '\0';
}
void input()//
输入
{
cin>>line;
if(biao == 0)
tackle_fuhao();//
处理负号
check();//
检查表达式是否合法
}
void introce()//
对计算器的符号功能的简要介绍
{
cout<<"
计算器简要介绍
"<<endl;
cout<<"C(cos)
S(sin)
T(tan)
a(arccos)
c(arcsin) "<<endl;
cout<<"7
8
9
/
on
t(arctan) "<<endl;
cout<<"4
5
6
*
%
L(log)"<<endl;
cout<<"1
2
3
-
M(M+)
Q(sqrt)
"<<endl;
cout<<"0
.
+
^(
乘方
) F(off)
Enter(=) "<<endl;
cout<<"
对于对数输入
L2_5
表示以
2
为底
5
的对数
"<<endl;
cout<<"M(
在前面结果的基础上继续计算,
如:
上次结果为
10
,
现输入
+10.5*2)"<<endl;
cout<<"D(
清零并继续输入
)"<<endl;
cout<<"F(
计算机关闭
)"<<endl;
cout<<"
输入
P
就代表输入圆周率
,
输入
E
代表输入自然对数
"<<endl<<endl;
}
void print()
{
system("color 2");
cout<<"
欢迎使用本计算器
"<<endl;
cout<<"
输入一个字符串
on,
计算器开始启动
"<<endl;
}
void if_start()//
是否启动计算器
{
string start;
print();
while(cin>>start)
{
if(start != "on")
{
cout<<"
您所输入的字符无效
,
请按照介绍的继续输入
:"<<endl;
continue;
}
else
break;
}
if(start == "on")
{
system("color 5");//
颜色的处理
system("cls");//
刷屏
}
introce();//
对计算器的简要介绍
cout<<"
现在
,
请输入您所要计算的表达式
"<<endl;
input();//
输入所要计算的表达式
}
int main()
{
if_start();//
调用是否启动计算器函数
return 0;
}
r = acos(one);
else if(cc == 's')
r = asin(one);
else if(cc == 't')
r = atan(one);
10. 不懂急,请问javascript对象的问题
上楼回答的很不错了你看看这一个纯JavaScript教程网站吧
我就是靠他学的http://www.ijavascript.cn/
JavaScript 是使用“对象化编程”的,或者叫“面向对象编程”的。所谓“对象化编程”,意思是把 JavaScript 能涉及的范围划分成大大小小的对象,对象下面还继续划分对象直至非常详细为止,所有的编程都以对象为出发点,基于对象。小到一个变量,大到网页文档、窗口甚至屏幕,都是对象。这一章将“面向对象”讲述 JavaScript 的运行情况。
对象的基本知识
对象是可以从 JavaScript“势力范围”中划分出来的一小块,可以是一段文字、一幅图片、一个表单(Form)等等。每个对象有它自己的属性、方法和事件。对象的属性是反映该对象某些特定的性质的,例如:字符串的长度、图像的长宽、文字框(Textbox)里的文字等等;对象的方法能对该对象做一些事情,例如,表单的“提交”(Submit),窗口的“滚动”(Scrolling)等等;而对象的事件就能响应发生在对象上的事情,例如提交表单产生表单的“提交事件”,点击连接产生的“点击事件”。不是所有的对象都有以上三个性质,有些没有事件,有些只有属性。引用对象的任一“性质”用“<对象名>.<性质名>”这种方法。
基本对象
现在我们要复习以上学过的内容了——把一些数据类型用对象的角度重新学习一下。
Number “数字”对象。这个对象用得很少,作者就一次也没有见过。不过属于“Number”的对象,也就是“变量”就多了。
属性
MAX_VALUE 用法:Number.MAX_VALUE;返回“最大值”。
MIN_VALUE 用法:Number.MIN_VALUE;返回“最小值”。
NaN 用法:Number.NaN 或 NaN;返回“NaN”。“NaN”(不是数值)在很早就介绍过了。
NEGATIVE_INFINITY 用法:Number.NEGATIVE_INFINITY;返回:负无穷大,比“最小值”还小的值。
POSITIVE_INFINITY 用法:Number.POSITIVE_INFINITY;返回:正无穷大,比“最大值”还大的值。
方法
toString() 用法:<数值变量>.toString();返回:字符串形式的数值。如:若 a == 123;则 a.toString() == '123'。
String 字符串对象。声明一个字符串对象最简单、快捷、有效、常用的方法就是直接赋值。
属性
length 用法:<字符串对象>.length;返回该字符串的长度。
方法
charAt() 用法:<字符串对象>.charAt(<位置>);返回该字符串位于第<位置>位的单个字符。注意:字符串中的一个字符是第 0 位的,第二个才是第 1 位的,最后一个字符是第 length - 1 位的。
charCodeAt() 用法:<字符串对象>.charCodeAt(<位置>);返回该字符串位于第<位置>位的单个字符的 ASCII 码。
fromCharCode() 用法:String.fromCharCode(a, b, c...);返回一个字符串,该字符串每个字符的 ASCII 码由 a, b, c... 等来确定。
indexOf() 用法:<字符串对象>.indexOf(<另一个字符串对象>[, <起始位置>]);该方法从<字符串对象>中查找<另一个字符串对象>(如果给出<起始位置>就忽略之前的位置),如果找到了,就返回它的位置,没有找到就返回“-1”。所有的“位置”都是从零开始的。
lastIndexOf() 用法:<字符串对象>.lastIndexOf(<另一个字符串对象>[, <起始位置>]);跟 indexOf() 相似,不过是从后边开始找。
split() 用法:<字符串对象>.split(<分隔符字符>);返回一个数组,该数组是从<字符串对象>中分离开来的,<分隔符字符>决定了分离的地方,它本身不会包含在所返回的数组中。例如:'1&2&345&678'.split('&')返回数组:1,2,345,678。关于数组,我们等一下就讨论。
substring() 用法:<字符串对象>.substring(<始>[, <终>]);返回原字符串的子字符串,该字符串是原字符串从<始>位置到<终>位置的前一位置的一段。<终> - <始> = 返回字符串的长度(length)。如果没有指定<终>或指定得超过字符串长度,则子字符串从<始>位置一直取到原字符串尾。如果所指定的位置不能返回字符串,则返回空字符串。
substr() 用法:<字符串对象>.substr(<始>[, <长>]);返回原字符串的子字符串,该字符串是原字符串从<始>位置开始,长度为<长>的一段。如果没有指定<长>或指定得超过字符串长度,则子字符串从<始>位置一直取到原字符串尾。如果所指定的位置不能返回字符串,则返回空字符串。
toLowerCase() 用法:<字符串对象>.toLowerCase();返回把原字符串所有大写字母都变成小写的字符串。
toUpperCase() 用法:<字符串对象>.toUpperCase();返回把原字符串所有小写字母都变成大写的字符串。
Array 数组对象。数组对象是一个对象的集合,里边的对象可以是不同类型的。数组的每一个成员对象都有一个“下标”,用来表示它在数组中的位置(既然是“位置”,就也是从零开始的啦)。
数组的定义方法:
var <数组名> = new Array();
这样就定义了一个空数组。以后要添加数组元素,就用:
<数组名>[<下标>] = ...;
注意这里的方括号不是“可以省略”的意思,数组的下标表示方法就是用方括号括起来。
如果想在定义数组的时候直接初始化数据,请用:
var <数组名> = new Array(<元素1>, <元素2>, <元素3>...);
例如,var myArray = new Array(1, 4.5, 'Hi'); 定义了一个数组 myArray,里边的元素是:myArray[0] == 1; myArray[1] == 4.5; myArray[2] == 'Hi'。
但是,如果元素列表中只有一个元素,而这个元素又是一个正整数的话,这将定义一个包含<正整数>个空元素的数组。
注意:JavaScript只有一维数组!千万不要用“Array(3,4)”这种愚蠢的方法来定义 4 x 5 的二维数组,或者用“myArray[2,3]”这种方法来返回“二维数组”中的元素。任意“myArray[...,3]”这种形式的调用其实只返回了“myArray[3]”。要使用多维数组,请用这种虚拟法:
var myArray = new Array(new Array(), new Array(), new Array(), ...);
其实这是一个一维数组,里边的每一个元素又是一个数组。调用这个“二维数组”的元素时:myArray[2][3] = ...;
属性
length 用法:<数组对象>.length;返回:数组的长度,即数组里有多少个元素。它等于数组里最后一个元素的下标加一。所以,想添加一个元素,只需要:myArray[myArray.length] = ...。
方法
join() 用法:<数组对象>.join(<分隔符>);返回一个字符串,该字符串把数组中的各个元素串起来,用<分隔符>置于元素与元素之间。这个方法不影响数组原本的内容。
reverse() 用法:<数组对象>.reverse();使数组中的元素顺序反过来。如果对数组[1, 2, 3]使用这个方法,它将使数组变成:[3, 2, 1]。
slice() 用法:<数组对象>.slice(<始>[, <终>]);返回一个数组,该数组是原数组的子集,始于<始>,终于<终>。如果不给出<终>,则子集一直取到原数组的结尾。
sort() 用法:<数组对象>.sort([<方法函数>]);使数组中的元素按照一定的顺序排列。如果不指定<方法函数>,则按字母顺序排列。在这种情况下,80 是比 9 排得前的。如果指定<方法函数>,则按<方法函数>所指定的排序方法排序。<方法函数>比较难讲述,这里只将一些有用的<方法函数>介绍给大家。
按升序排列数字:
function sortMethod(a, b) {
return a - b;
}
myArray.sort(sortMethod);
按降序排列数字:把上面的“a - b”该成“b - a”。
有关函数,请看下面。
Math “数学”对象,提供对数据的数学计算。下面所提到的属性和方法,不再详细说明“用法”,大家在使用的时候记住用“Math.<名>”这种格式。
属性
E 返回常数 e (2.718281828...)。
LN2 返回 2 的自然对数 (ln 2)。
LN10 返回 10 的自然对数 (ln 10)。
LOG2E 返回以 2 为低的 e 的对数 (log2e)。
LOG10E 返回以 10 为低的 e 的对数 (log10e)。
PI 返回π(3.1415926535...)。
SQRT1_2 返回 1/2 的平方根。
SQRT2 返回 2 的平方根。
方法
abs(x) 返回 x 的绝对值。
acos(x) 返回 x 的反余弦值(余弦值等于 x 的角度),用弧度表示。
asin(x) 返回 x 的反正弦值。
atan(x) 返回 x 的反正切值。
atan2(x, y) 返回复平面内点(x, y)对应的复数的幅角,用弧度表示,其值在 -π 到 π 之间。
ceil(x) 返回大于等于 x 的最小整数。
cos(x) 返回 x 的余弦。
exp(x) 返回 e 的 x 次幂 (ex)。
floor(x) 返回小于等于 x 的最大整数。
log(x) 返回 x 的自然对数 (ln x)。
max(a, b) 返回 a, b 中较大的数。
min(a, b) 返回 a, b 中较小的数。
pow(n, m) 返回 n 的 m 次幂 (nm)。
random() 返回大于 0 小于 1 的一个随机数。
round(x) 返回 x 四舍五入后的值。
sin(x) 返回 x 的正弦。
sqrt(x) 返回 x 的平方根。
tan(x) 返回 x 的正切。
Date 日期对象。这个对象可以储存任意一个日期,从 0001 年到 9999 年,并且可以精确到毫秒数(1/1000 秒)。在内部,日期对象是一个整数,它是从 1970 年 1 月 1 日零时正开始计算到日期对象所指的日期的毫秒数。如果所指日期比 1970 年早,则它是一个负数。所有日期时间,如果不指定时区,都采用“UTC”(世界时)时区,它与“GMT”(格林威治时间)在数值上是一样的。
定义一个日期对象:
var d = new Date;
这个方法使 d 成为日期对象,并且已有初始值:当前时间。如果要自定初始值,可以用:
var d = new Date(99, 10, 1); //99 年 10 月 1 日
var d = new Date('Oct 1, 1999'); //99 年 10 月 1 日
等等方法。最好的方法就是用下面介绍的“方法”来严格的定义时间。
方法
以下有很多“g/set[UTC]XXX”这样的方法,它表示既有“getXXX”方法,又有“setXXX”方法。“get”是获得某个数值,而“set”是设定某个数值。如果带有“UTC”字母,则表示获得/设定的数值是基于 UTC 时间的,没有则表示基于本地时间或浏览期默认时间的。
如无说明,方法的使用格式为:“<对象>.<方法>”,下同。
g/set[UTC]FullYear() 返回/设置年份,用四位数表示。如果使用“x.set[UTC]FullYear(99)”,则年份被设定为 0099 年。
g/set[UTC]Year()返回/设置年份,用两位数表示。设定的时候浏览器自动加上“19”开头,故使用“x.set[UTC]Year(00)”把年份设定为 1900 年。
g/set[UTC]Month()返回/设置月份。
g/set[UTC]Date()返回/设置日期。
g/set[UTC]Day()返回/设置星期,0 表示星期天。
g/set[UTC]Hours()返回/设置小时数,24小时制。
g/set[UTC]Minutes()返回/设置分钟数。
g/set[UTC]Seconds()返回/设置秒钟数。
g/set[UTC]Milliseconds()返回/设置毫秒数。
g/setTime() 返回/设置时间,该时间就是日期对象的内部处理方法:从 1970 年 1 月 1 日零时正开始计算到日期对象所指的日期的毫秒数。如果要使某日期对象所指的时间推迟 1 小时,就用:“x.setTime(x.getTime() + 60 * 60 * 1000);”(一小时 60 分,一分 60 秒,一秒 1000 毫秒)。
getTimezoneOffset() 返回日期对象采用的时区与格林威治时间所差的分钟数。在格林威治东方的市区,该值为负,例如:中国时区(GMT+0800)返回“-480”。
toString() 返回一个字符串,描述日期对象所指的日期。这个字符串的格式类似于:“Fri Jul 21 15:43:46 UTC+0800 2000”。
toLocaleString() 返回一个字符串,描述日期对象所指的日期,用本地时间表示格式。如:“2000-07-21 15:43:46”。
toGMTString() 返回一个字符串,描述日期对象所指的日期,用 GMT 格式。
toUTCString() 返回一个字符串,描述日期对象所指的日期,用 UTC 格式。
parse() 用法:Date.parse(<日期对象>);返回该日期对象的内部表达方式。
全局对象
全局对象从不现形,它可以说是虚拟出来的,目的在于把全局函数“对象化”。在 Microsoft JScript 语言参考中,它叫做“Global 对象”,但是引用它的方法和属性从来不用“Global.xxx”(况且这样做会出错),而直接用“xxx”。
属性
NaN 一早就说过了。
方法
eval() 把括号内的字符串当作标准语句或表达式来运行。
isFinite() 如果括号内的数字是“有限”的(介于 Number.MIN_VALUE 和 Number.MAX_VALUE 之间)就返回 true;否则返回 false。
isNaN() 如果括号内的值是“NaN”则返回 true 否则返回 false。
parseInt() 返回把括号内的内容转换成整数之后的值。如果括号内是字符串,则字符串开头的数字部分被转换成整数,如果以字母开头,则返回“NaN”。
parseFloat() 返回把括号内的字符串转换成浮点数之后的值,字符串开头的数字部分被转换成浮点数,如果以字母开头,则返回“NaN”。
toString() 用法:<对象>.toString();把对象转换成字符串。如果在括号中指定一个数值,则转换过程中所有数值转换成特定进制。
escape() 返回括号中的字符串经过编码后的新字符串。该编码应用于 URL,也就是把空格写成“%20”这种格式。“+”不被编码,如果要“+”也被编码,请用:escape('...', 1)。
unescape() 是 escape() 的反过程。解编括号中字符串成为一般字符串。
函数函数的定义
所谓“函数”,是有返回值的对象或对象的方法。
函数的种类
常见的函数有:构造函数,如 Array(),能构造一个数组;全局函数,即全局对象里的方法;自定义函数;等等。
自定义函数
定义函数用以下语句:
function 函数名([参数集]) {
...
[return[ <值>];]
...
}
其中,用在 function 之后和函数结尾的大括号是不能省去的,就算整个函数只有一句。
函数名与变量名有一样的起名规定,也就是只包含字母数字下划线、字母排头、不能与保留字重复等。
参数集可有可无,但括号就一定要有。
参数 是函数外部向函数内部传递信息的桥梁,例如,想叫一个函数返回 3 的立方,你就要让函数知道“3”这个数值,这时候就要有一个变量来接收数值,这种变量叫做参数。
参数集是一个或多个用逗号分隔开来的参数的集合,如:a, b, c。
函数的内部有一至多行语句,这些语句并不会立即执行,而只当有其它程序调用它时才执行。这些语句中可能包含“return”语句。在执行一个函数的时候,碰到 return 语句,函数立刻停止执行,并返回到调用它的程序中。如果“return”后带有<值>,则退出函数的同时返回该值。
在函数的内部,参数可以直接当作变量来使用,并可以用 var 语句来新建一些变量,但是这些变量都不能被函数外部的过程调用。要使函数内部的信息能被外部调用,要么使用“return”返回值,要么使用全局变量。
全局变量 在 Script 的“根部”(非函数内部)的“var”语句所定义的变量就是全局变量,它能在整个过程的任意地方被调用、更改。
例
function addAll(a, b, c) {
return a + b + c;
}
var total = addAll(3, 4, 5);
这个例子建立了一个叫“addAll”的函数,它有 3 个参数:a, b, c,作用是返回三个数相加的结果。在函数外部,利用“var total = addAll(3, 4, 5);”接收函数的返回值。
更多的时候,函数是没有返回值的,这种函数在一些比较强调严格的语言中是叫做“过程”的,例如 Basic 类语言的“Sub”、Pascal 语言的“procere”。
属性
arguments 一个数组,反映外部程序调用函数时指定的参数。用法:直接在函数内部调用“arguments”。