发表于: 2019-03-09 20:23:37

2 563


今天完成的事情:

修改任务中的bug,之前写的时候没注意,点击之后的按钮数字还是2

else if (circle <= 2 * allNum) { //查看过程中
   var thisNum = Math.ceil(circle / 2); //查看当前身份数
   $('#circle').text(thisNum);
   if (circle % 2 === 1) {//按钮内容
       $('.base').text(`查看${thisNum}号身份`);
   }
   else {
       $('.base').text(`隐藏并传递给${thisNum + 1}号`);
   }
   $('.role').text(arr[circle / 2 - 1]);
   $('#hidden').toggle();
   $('#appear').toggle();
}
if (circle === 2 * allNum) {
   // 点击到头,按钮显示进入法官页面
   $('.base').text(`法官查看`);
}


明天计划的事情:明天开始任务五


遇到的问题:算不上困难吧,就是上面提过的小bug,我已经自己解决了。

 
收获:今天没有学什么新的知识,就是新来试学的师弟有些问题,然后开导他了挺长时间。

                                                                                     任务四总结

  终于把这个桌游写完了,回头想想跟做梦一样,刚开始的时候以为自己写不出来,是不是要被这个任务给劝退了,现在想想从这个任务中真的是成长了不少,也学到了不少,在这里真的是很感谢我的师兄们,一直不厌其烦的为我解决问题,甚至写任务四杀人页面的时候,做一个功能就要向师兄请教一次,到最后游戏结果的页面才突然感觉自己成长了不少,师兄稍微一提示,我就知道怎么做了,而且最后一个页面大部分都是独立完成的。

                                                                                       深度思考

1.对一个数组 filter、some、map、foreach的操作分别有什么作用?

使用JavaScript数组常常需要对数组进行遍历、迭代操作。而我们常用的就是for语句对数组进行迭代。然而在ECMAscript5已经为数组定义了5个迭代的方法,分别是:filter、some、map、foreach、every,下面我们讲讲它们的具体作用:

every(): 对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true ;

some(): 对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true;

通过 demo,我们了解到对于 every() ,它返回的是false,因为存在不符合条件的值。

而对于some() ,结果就为true,因为至少存在一项符合条件的值;

filter(): 对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。

通过调用 filter() 创建并返回了包含符合条件的数组,因为传入的函数对他们每一项都返回true。这个方法对查询符合某些条件的所有数组项非常有用。

map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。

map()也返回一个数组,而这个数组的每一项都是在原始数组中的对应项上运行传入函数的结果;

forEach():对数组中的每一项运行给定函数,这个方法并没有返回值 ;

通过demo可以看出 forEach() ,只是对每个数组项运行指定的函数体,这个迭代方式并没有返回值,本质上与使用for循环迭代数组一样

循环(loop),指的是在满足条件的情况下,重复执行同一段代码。比如,while语句。

迭代(iterate),指的是按照某种顺序逐个访问列表中的每一项。比如,for语句。

遍历(traversal),指的是按照一定的规则访问树形结构中的每个节点,而且每个节点都只访问一次。

递归(recursion),指的是一个函数不断调用自身的行为。比如,以编程方式输出著名的斐波纳契数列。

有了以上定义,这几个概念之间的区别其实就比较清楚了。至于它们之间的联系,严格来讲,它们似乎都属于算法的范畴。

换句话说,它们只不过是解决问题的不同手段和方式,而本质上则都是计算机编程中达成特定目标的途径。

 2.如何使用HBuilder打包app?

HBuilder是DCloud(数字天堂)推出的一款支持HTML5的Web开发IDE。该软件既可以支持web代码编写,也可以将已经编写好的项目代码打包为手机APP。

HBuilder提供的打包有云端打包和本地打包两种,云端打包的特点是DCloud官方配置好了原生的打包环境,可以把HTML等文件编译为原生安装包。

1,下载HBuilder,注册并登陆。首先打开“文件”-“新建”-“移动APP”,输入“应用名称”,“位置”可以根据需要自己选择即可,“选择模板”建议选择空模板;

2,新建完成后, 在项目管理器会显示新建的项目目录,其中css,img,js和index.html这几个文件可删可改可替换。

unpackage文件夹是放置app图标和启动界面的图片。

manifest.json文件是移动App的配置文件,用于指定应用的显示名称、图标、应用入口文件地址及需要使用的设备权限等信息,用户可通过HBuilder的可视化界面视图或者源码视图来配置移动App的信息。

3,如果删除了css,img,js文件夹和index.html文件,就把其他自己的项目文件对应复制到文件夹中,注意html文件中的引用路径需要保持正确。

如下图自己拷贝的项目:

 

4, 文件复制完成后,刷新更新下,双击打开manifest.json文件来配置App。

appid:点击云端获取。版本号:根据需要来编辑。页面入口:默认是index.html,根据自己项目需要,更改APP的启动页面。应用描述:自己随便填。应用是否全屏显示:勾上就全屏显示。

5,图标配置:点击页面下方的图标配置,配置APP显示图标。

1)点击"+"号的正方形方框,选择图标素材的路径找到图标素材,再点击" 自动生成所有图标并替换"按钮,完成图标生成和替换。

2),生成的图标自动在unpackage文件夹下

6,启动图片(splash)配置,点击切换到启动图片配置

1),启动选项:默认

2),启动图片设置,根据自己需要是Android还是iOS平台,再根据不同设备对应做出启动图片

3),在unpackage→res文件下新建个文件命名"splash",把做好的启动图片放到这个文件里面。

4),在启动图片设置里点击"选择",找到刚放进来的启动图片

7,SDK配置:有需要就配置,没有就默认就行。

8,模块权限配置:有需要就配置,没有就默认就行。

9,页面引用关系:

首先点击“扫描代码”,再点击左边index.html文件

该功能是什么意思:点击左侧html文件,右侧会显示不同的文件,图片等。可以表示左侧html文件加载时所需要的资源。

10,代码视图:在代码视图里查看设置是否正确,确定后ctrl+s保存好。

11,设置好配置选项,正式进入打包阶段

HBuilder里点:"发行"-"发行为原生安装包"开始打包

这里介绍一下iOS打包

1),这里如果选择越狱包就不需要苹果证书,一路默认设置就可以打包成功,但是打包的App只能安装在越狱过的手机,没越狱安装不了。

2),如果使用苹果证书,这里推荐一个申请iOS证书的工具 Appuploader。免苹果付费开发者账号,直接使用普通苹果id,就能使用Appuploader申请ios测试证书,打包ipa安装到非越狱设备。

工具的安装网址:http://www.applicationloader.net/blog/zh/72.html

免开发者账号申请iOS证书教程:http://www.applicationloader.net/blog/zh/1073.html

 

12,提交成功后点击确定,就可以查看App打包状态

等打包成功,就可以点手动下载,通过第三方工具 苹果助手安装到ipad上了。

13,调试和安装模拟器

如果你需要在电脑本机进行调试那就需要安装模拟器,请参考http://ask.dcloud.net.cn/article/151如何安装配置手机模拟器,或者在HBuilder里→→运行→→手机运行→→如何安装配置手机模拟器进入查看。

如果需要安装到手机进行真机调试,把手机用数据线连接到电脑,然后重新启动HBuilder→→运行→→手机运行→→连接上真机。

3.如何使用phonegap打包app?

使用PhoneGap搭建Android开发的项目整体步骤如下:

  1. 安装java环境。

  2. 安装ant构建工具。

  3. 安装android的开发环境并配置环境变量。

  4. 安装Node.js环境并配置环境变量。

  5. 安装git

  6. 使用npm安装PhoneGap全局环境。

  7. 使用PhoneGap命令创建PhoneGap项目。

  8. 将PhoneGap编译为android项目。

  9. 将上述项目导入ADT进行后续开发。

  10. 安装.apk文件

其实官网给出的安装过程忽略了很多步骤(因为这里是Andriod环境,所以才会比官网的例子多出不少步骤),像我这种前端开发人员,电脑里可是连java都没装的,下面就详细讲解这些步骤,并最终生成apk文件。

 安装Java环境

这点不用我讲,网上一搜一大堆,而且很多程序员电脑里面都是有java环境的,需要强调的是安装java的环境要和后面下载andriod开发环境一致,不然会报错,要保证都是32位或64位,笔者就装了个64位jdk然后,安卓环境是32位的,运行不成功。

资源

jdk 下载:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

配置java环境:http://jingyan.baidu.com/article/ed15cb1b2ed02a1be369818a.html

 安装Ant构建工具

Adobe将PhoneGap已经放到Apache名下进行开源,并且还改了个名字,ant可以apache下的构建工具,所以……需要先安装ant才可以,安装过程其实非常简单,第一个就是下载,选择适合自己的版本,因为我的环境是win7 所以下载zip格式的就可以了。

然后将zip文件解压到任意目录,并添加环境变量,具体可以参看这里

  1. 将bin目录添加到path里面
  2. 添加ANT_HOME变量为ant的根目录
  3. 确保安装了jdk并配置好了JAVA_HOME

然后保存环境变量,打开命令行输入 ant -version 你应该看见类似下面的输出,那恭喜成功了,可以进行下一步了,如果未成功,可百度下错误原因:

 下载Andriod开发环境并配置环境变量

首先就是来这里下载环境,然后是安装,其实就是解压到任意目录,可以看这里,接下来需要添加环境变量,将sdk目录下的platform-tools 和 tools添加到path里。


然后你还需要设置avd,打开AVD Manager,点击新建,然后设置一些参数即可,由于我也不是搞安卓的,所以吗你要想深入了解需自行研究。

 安装git

git是我非常喜欢的版本控制工具,我电脑上自带的是github for windows,只需将其git命令添加到path即可,如果你没有安装git我建议你安装mysygit,安装过程中记得勾上将git添加仅path选项。如果你安装的其他git工具,请确保将git命令加入path,因为安装phonegap过程会用到git命令。

这里下载mysygit,注意下载过程非常缓慢(没办法了谁让我们在天朝呢,以前mysygit在google code上的时候速度更慢,下载迁移到github速度已经快很多了)。

如果你对git感兴趣,我建议你加入我的群一起交流,GitHub家园② 193091696,由于1群已满,群共享里也有mysygit的最新pre版,下载速度会是github上的几百倍吧!!!!

 安装Node.js环境并配置环境变量

来这里下载你需要的版本,windows建议下载.msi安装包,自带npm,无需配置环境变量,如果你下载.exe的话下载的知识node,还需要自行配置环境变量和安装npm。现在的node安装过程真的非常简单了。

 使用npm安装PhoneGap全局环境

到这里就可以安装官网上的提供的教程来了,打开刚刚安装的node的命令行工具,然后输入 npm install -g phonegap,将会自动安装phonegap,需要注意的是安装过程非常缓慢,因为安装期间回到用到git命令去下载文件(不是git慢,而是外网慢)。安装完成后会提示安装成功,当然你也可以输入 phonegap -v,你将会看到如下输出,说明你安装成功了:`

 使用PhoneGap命令创建PhoneGap项目

接下来将路径切到任意目录,输入 <code>phonegap create my-app 你将会看到如下画面:</code>

 将PhoneGap编译为android项目

接下来先切换到myapp1目录,然后运行phonegap run andriod

cd myapp
phonegap run android

会出现很多构建信息,成功后会自动启动adk模拟器

如果你不想运行安卓模拟器,而只想构将项目那么可以,你只需运行 phonegap build android 即可。

 将上述项目导入ADT进行后续开发

启动ADT中的eclipse,然后选择File-New-Project,在打开的“New Project”向导中选择Android->Android Project from Existing Code,并选择Next

在下一步的导航页中Root Directory选择刚才创建的my-app/platforms/android文件夹,下方Projects会出现两个项目,都勾选,但是不要勾选Copy projects into workspace选项。

选择Finish完成上述导入

话说上面的导入过程是复制粘贴的,笔者导入的时候点击finished就是不起作用,不知为何,比较郁闷,不知你是否也会遇到同样的事情。

 安装.apk文件

项目目录下的platformsandroidant-build 里已经生成了对应的apk文件,将其导入手机即可安装。

4.如何验证程序是否完成,测试以及修正Bug

在日常中,我们码代码都是按照需求来的,为了验证我们的工作成果是否符合项目的需求,那么验证程序是否完成、测试以及修复bug就成了我们工作中非常重要的流程。

1.什么样的程序是完成的程序

从需求的角度看:满足用户的全部需求

从程序的角度看:代码不存在明显bug,结构明晰,逻辑通顺,有一定的优化

从UI图的角度看:较为完美的还原了UI图的设计

从后期版本维护迭代的角度看:注释完备,稳定性好,不加班的代码就是好代码

2.测试:测试是使用人工操作或者软件自动运行的方式来检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别的过程。

软件测试的方法

按照测试范围,可以分为模块测试和整体联调

按照测试条件,可以分为正常操作情况测试和异常情况测试

按照测试的输入范围,可以分为全覆盖测试和抽样测试

测试方式之间的区别

模块测试:针对设计中的一个一个模块来进行测试的,目的是保证每个模块作为一个单元能正确运行,所以模块测试通常又被称为单元测试。在这个测试步骤中所发现的往往是编码和详细设计的错误。

整体联调:测试模块间接口的正确性、各模块间的数据流和控制流是否按照设计实现其功能、以及集成后整体功能的正确性。

正常操作情况测试:根据正确的操作流程对单独的模块或整体进行测试,确定被测对象可以良好运行

异常情况测试:异常情况,可能会包括数据库异常,系统异常,用户异常操作等情况

3.一些测试的概念

成熟性:软件产品要避免由软件中错误而导致失效的能力

容错性:在软件失效或者违反规定的接口的情况下,软件产品维持规定的性能级别的能力

易恢复性:在发生故障的情况下,软件重建规定的性能级别并恢复受直接影响的数据的能力

可靠性依从性:软件产品依附于同可靠性相关的标准、约定或规定的能力

全覆盖测试:对于被测对象全面,整体,多维度的测试,受限于时间和人力成本,除非被测对象级别很高,不然不会采用这种测试方式

抽样测试:针对功能及模块随机抽取被测对象

5.如何理解JS作用域与作用域链?

变量作用域

在JavaScript中全局变量的作用域比较简单,它的作用域是全局的,在代码的任何地方都是有定义的。然而函数的参数和局部变量只在函数体内有定义。另外局部变量的优先级要高于同名的全局变量,也就是说当局部变量与全局变量重名时,局部变量会覆盖全局变量(如下面例子)。

   var num = 1;            //声明一个全局变量
   function func() {
      var num = 2;        //声明一个局部变量
       return num;
   }
   console.log(func());    //输出:2

 注:声明局部变量时一定要使用var,否则,解释器会将该变量当做全局对象window的属性。

函数作用域

在JavaScript中变量的作用域,并非和C、Java等编程语言似得,在变量声明的代码段之外是不可见的,我们通常称为块级作用域,然而在JavaScript中使用的是函数作用域(变量在声明它们的函数体以及这个函数体嵌套的任意函数体都是有定义的)。(如下面的例子)

 function func() {
            console.log(num);           //输出:undefined,而非报错,因为变量num在整个函数体内都是有定义的
            var num = 1;                //声明num 在整个函数体func内都有定义
            console.log(num);           //输出:1        }
        func();

注:JavaScript的函数作用域是指在在函数内声明的所有变量在函数体内始终是可见的,也就是说在函数体内变量声明之前就已经可用了。

作为属性的变量

当声明一个全局变量的时候,实际上是定义了全局对象window的一个属性。

  var num = 1;            //声明全变量num
        alert(window.num)       //输出:1 声明的全局变量实际上就是声明了一个window对象的属性

 

作用域链

在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。

当一个函数创建后,它实际上保存一个作用域链,并且作用域链会被创建此函数的作用域中可访问的数据对象填充。例如定义下面这样一个函数:

 function func() {            var num = 1;
            alert(num);
        }
        func();

在函数func创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量,如下图所示(注意:图片只例举了全部变量中的一部分):

 函数add的作用域将会在执行时用到。例如执行如下代码:

执行此函数时会创建一个称为“运行期上下文(execution context)”(有人称为运行环境)的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。

  这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。新的作用域链如下图所示:

6.杀人和投票的业务逻辑上有什么区别?

业务逻辑是什么?
不同的项目有不同的功能,不同的功能需要不同的实现,实现这些核心功能的代码就叫业务逻辑。

让你实现一个功能,给你两个数,让你获取它的和,你所写的如何才能获得任意给定的两个数的和,这个程序实现过程称为业务逻辑处理。

就像家里规矩–“吃饭前必须洗手”“有客人来要起立”-就是业务逻辑的生活化实例。

简单来就是在怎么做事(how to do), 比方说你去餐馆吃饭, 你点了个炒米粉,服务员给你下单,厨房见到单后下锅给你炒,你吃完后付账。这一些列动作都可以说是业务逻辑。

业务逻辑就是客户的逻辑。在 N 层架构的系统中,经常会提到这些名词。

表现层(Presentation layer) 业务逻辑层(Application layer)数据访问层(Data layer) ,在一个系统开发过程中,后台做一些处理,如果成功,则跳转到 success_xxx 页面,如果失败,则跳转到fail_xxx 页面,如果系统抛出了异常,则跳转到 5xx 页面,…… 这些属于页面逻辑。

还有一些持久层的逻辑,也就是对数据库的操作。

业务逻辑是核心逻辑,只关注用户的业务,比如管理系统和财务系统,需要处理的业务肯定不一样,但是页面的跳转大致相同,对于持久层的操作也差不多。如果你使用了 SSH 框架,那么 hibernate 和 struts 的代码有很大一部分可以复用

业务逻辑(BL Action)不关心页面如何跳转,只是简单的返回成功,或是失败,或是异常,struts 框架根据配置文件跳转到相应的页面。

业务逻辑也不关心数据如何存储,是存储在文件系统,还是存储在数据库系统。是存储在MySQL,还是NoSQL。也不关系到底用没用缓存。

杀人和投票页面区别之处

杀人:点击杀手弹出提示框;

投票:杀手,平民都可以点击;

杀人:确定后传值用于刷新法官页面到步骤1完成的状态

投票:确定后传值用于重置有限状态机状态

杀人:确定后天数不变,如果游戏结束天数+1且传个值用于隐藏游戏进程当天白天的信息

投票:确定后天数+1,如果胜利天数不变

杀人和投票页面相同之处

1.根据法官页面传来值改变文本

2.点击玩家提取序号,确定后存入死亡玩家数组,存活杀手或平民-1

3.不选择玩家不能离开

4.死亡玩家变色,且移除点击事件

5.胜利判断

7.如何实现数组深拷贝和浅拷贝?

javascript分原始类型与引用类型。Array是引用类型,直接用“=”号赋值的话,只是把源数组的地址(或叫指针)赋值给目的数组,并没有实现数组的数据的拷贝。这种方式的实现属于浅拷贝。

深拷贝是开辟新的储存空间,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。

一维数组深拷贝slice和concat方法

1.  slice()

slice()语法:arrayObj.slice(start,[end]);

start:必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1指最后一个元素,-2 指倒数第二个元素,以此类推。

end:可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。

返回值:返回一个新的数组,包含从start 到 end (不包括该元素)的arrayObject 中的元素(如果 end 未被规定,那么slice() 方法会选取从 start 到数组结尾的所有元素)。

2.concat()方法

   concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。

语法:arrayObject.concat(arrayX,arrayX,......,arrayX)

说明:返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组。

 jquery中数组深拷贝办法

jquery.extend()

语法:jQuery.extend([deep ], target, object1 [, objectN ] )

8.简述JS中的面向对象编程 

在 JavaScript 中,大多数事物都是对象, 从作为核心功能的字符串和数组,到建立在 JavaScript 之上的浏览器

API。你甚至可以自己创建对象,将相关的函数和变量封装打包成便捷的数据容器。理解这种面向对象(object-oriented, OO) 的特性对于进一步学习 JavaScript

语言知识是必不可少的。这个模块将帮助你了解“对象”,先详细介绍对象的设计思想和语法,再说明如何创建对象。

然后,所谓面向对象编程,我觉得主要有以下几个知识点

1.理解对象以及访问对象的两种表示法

2.'this'的含义

3.面向对象的程序设计

4.构造函数和对象实例

5.原型链

6.prototype 属性

7.constructor 属性

8.原型式继承

那什么是对象呢?

对象是一个包含相关数据和方法的集合(通常由一些变量和函数组成,我们称之为对象里面的属性和方法)。我们来看一个例子:

var person = {

    name: ['Bob', 'Smith'],

    age: 32,

    gender: 'male',

    interests: ['music', 'skiing'],

    bio: function () {

        alert(this.name[0] + ' ' + this.name[1]+ ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1]+ '.');

    },

    greeting: function () {

        alert('Hi! I\'m ' + this.name[0]+ '.');

    }

};

这就是一个典型的对象的例子,作为一个人,具有姓名,年龄,性别,爱好等等属性,而且有各种方法,会打招呼(greeting()),会做饭。

而我们想要访问到这个属性的话,就要用到点表示法,person.age.调用方法,也是同样,person.greeting();即可

我们来看一下括号表示法和点表示法的区别

function append() {

    var attr=$("#name").val();

    var num=$("#value").val();

   person[attr]=num;

    console.log(person);

}

 

我们通过括号表示法,可以给对象添加新的key和value,

继续添加

我们就添加了键值对的名字,这是点表示法做不到的,点表示法不能使用变量作为属性名。

2.this的指向

在对象里,关键字"this"指向了当前代码运行时的对象,比如上面这个代码,this实际上指向了当前的对象。所以当我们调用这个方法的时候,greeting()

greeting: function (){

    alert('Hi! I\'m ' + this.name[0] + '.');

}

会弹出当前对象的名字

3.面向对象的程序设计

最基本的 OOP 思想就是我们想要在我们的程序中使用对象来表示现实世界模型,并提供一个简单的方式来访问它的功能,否则很难甚至不能实现.

对象可以包含相关的数据和代码,这些代表现实世界模型的一些信息或者功能,或者它特有的一些行为.对于一个人(person)来说,我们能在他们身上获取到很多信息(他们的住址,身高,鞋码,基因图谱,护照信息,显著的性格特征等等),然而,我们仅仅需要他们的名字,年龄,性别,兴趣这些信息,然后,我们会基于他们的这些信息写一个简短的介绍关于他们自己,在最后我们还需要教会他们打招呼。以上的方式被称为抽象-为了我们编程的目标而利用事物的一些重要特性去把复杂的事物简单化

比如对于人这个类来说,它具有各种基本属性和方法,人与人之间的区别只是属性的值不一样,这样我们就简单构造了一个类来描述真实的世界。

  对于前端来说,我们在javaScript里用构造函数来实现面向对象编程。废话不多说,来看一个例子吧。

 function Person(first, last, age, gender,interests) {

    this.name = {

        first,

        last

    };

    this.age = age;

    this.gender = gender;

    this.interests = interests;

}

我们首先定义了一个类别为人的构造函数,当我们想要描述一个人的时候,给他传进去参数就可以了,比如

var person1=new Person('Chris','Martin',32,'male',['music','guitar']);

我们首先定义了Christ Martin,

再定义一个人

var person2=new Person('Gwyneth','Paltrow','35','female',['ironman','movie'])

 

是不是很方便快捷。

4.原型链

JavaScript 常被描述为一种基于原型的语言 (prototype-based

language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype

chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。

比如当我们调用person1.valueOf方法的时候,先是在person1里查找valueOf()方法,没找到,继续找它的原型,也就是构造函数Person,还是没找到,接着去对象的方法里去找,找到了,然后就成功调用了。

5.constructor和prototype属性

prototype 属性:继承成员被定义的地方,继承的属性和方法是定义在 prototype 属性之上的。然后每个对象实例都具有 constructor 属性,它指向创建该实例的构造器函数。

9.简述JS中this的指向

1. 全局作用域或者普通函数中 this 指向全局对象 window。

//直接打印

console.log(this) //window

//function声明函数

function bar () {console.log(this)}

bar() //window

//function声明函数赋给变量

var bar = function () {console.log(this)}

bar() //window

//自执行函数

(function () {console.log(this)})(); //window

2. 方法调用中谁调用 this 指向谁

//对象方法调用

var person = {

  run: function () {console.log(this)}

}

person.run() // person

//事件绑定

var btn = document.querySelector("button")

btn.onclick = function () {

  console.log(this) // btn

}

//事件监听

var btn = document.querySelector("button")

btn.addEventListener('click', function () {

  console.log(this) //btn

})

//jquery的ajax

$.ajax({

  self: this,

  type: "get",

  url: url,

  async: true,

  success: function (res) {

    console.log(this) // this指向传入$.ajxa()中的对象

    console.log(self) // window

  }

});

//这里说明以下,将代码简写为$.ajax(obj) ,this指向obj,在obj中this指向window,因为在在success方法中,独享obj调用自己,所以this指向obj

3. 在构造函数或者构造函数原型对象中 this 指向构造函数的实例

//不使用new指向window

function Person(name) {

  console.log(this) // window

  this.name = name;

}

Person('inwe')

//使用new

function Person(name) {

  this.name = name

  console.log(this) //people

  self = this

}

var people = new Person('iwen')

console.log(self === people) //true

//这里new改变了this指向,将this由window指向Person的实例对象people

4. 箭头函数中指向外层作用域的 this

var obj = {

  foo() {

    console.log(this);

  },

  bar: () => {

    console.log(this);

  }

}

obj.foo() // {foo: ƒ, bar: ƒ}

obj.bar() // window

10.json是什么,如何处理转义?

在JSON出现之前,人们一直用XML来传递数据。因为XML是一种纯文本格式,所以它适合在网络上交换数据。XML本身不算复杂,但是,加上DTD、XSD、XPath、XSLT等一大堆复杂的规范以后 ,XML使用起来很繁琐。后来,出现了JSON。JSON是道格拉斯·克罗克福特(DouglasCrockford)在2001年开始推广使用的数据格式,在2005年-2006年正式成为主流的数据格式,雅虎和谷歌就在那时候开始广泛地使用JSON格式。

JSON (JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。数据传输是我们在敲代码时,经常遇到的一个场景,前后端交互。给数据一个统一的格式有利于我们编写和解析数据。json,是一种数据格式,在与后端的数据交互中有较为广泛的应用。

JSON语法

数据在名称/值对中

数据由逗号分隔

大括号保存对象

中括号保存数组     

JSON值

数字(整数/浮点数)

字符串

布尔值(true/false)

数组(中括号中)

对象(大括号中)

null

例                  

var json = {"password":123456,"name":"myname","Booleans":true,"Array":[x,y,z],"object":{}}

                               

JSON嵌套

                  

                    myObj = {

                        "name":"jnshu",

                        "alexa":1000,

                        "sites": {

                            "site1":"www.jnshu.com",

                            "site2":"m.jnshu.com",

                            "site3":"c.jnshu.com"

                        }

                    }

                    console.log(myObj)

                  //输出结果:

                 // Object {name: "jnshu", alexa: 1000, sites: Object}

                  

              

JSON使用

JSON.parse()将字符串转化为对象

JSON.stringify()将对象转化为字符串

                      var str = '{ "name": "cxh", "sex": "man" }';//  JSON字符串

                      var obj = JSON.parse(str); //由JSON字符串转换为JSON对象

                        //读取

                      Alert(obj.name);

                      Alert(obj.sex);

                      var a = { "name": "cxh", "sex": "man" };//JSON对象

                      var b =JSON.stringify(a); //将JSON对象转化为JSON字符

11.如何使用Bootbox ? 

该库提供了模拟原生JavaScript的alert警告,confirm确认、prompt提示这三个对话框,另外Bootbox还有dialog自定义对话框。它们每个可以采取各种参数来定制标签和指定默认值,它们最基本用法如下:

alert是只有单个按钮的对话框,按ESC键或单击关闭按钮可关闭对话框。

bootbox.alert("Your message here…", function(){ /* your callback code */ }) 

1

Confirm是具有确定和取消按钮的对话框, 按ESC键或单击关闭将忽略对话框并调用回调函数,效果等同于单击取消按钮。 

需要注意的是,使用confirm时回调函数是必须的。

bootbox.confirm("Are you sure?", function(result){ /* your callback code */ })

1

prompt 是提示用户进行输入操作并确定或者取消的对话框, 按ESC键或单击关闭将忽略对话框并调用回调函数,效果等同于单击取消按钮。 同样,prompt中回调函数也是必须的。 

注意:prompt在使用options选项时需要title选项,并且不允许使用message选项。

bootbox.prompt("What is your name?", function(result){ /* your callback code */ }) 

1

dialog 一个完全自定义的对话框方法,它只接收一个参数 options 对象。也就是说按ESC键时,这个自定义对话框将不会自动关闭,需要使用onEscape函数手动实现此行为。

bootbox.dialog(options)

1

options至少要有message选项。

12.return的用法是什么?若用在for循环中,还会执行下一次循环吗?

return 语句从当前函数退出,并从那个函数返回一个值。

语法:

                return[()[expression][]];

                可选项 expression 参数是要从函数返回的值。如果省略,则该函数不返回值。

用 return 语句来终止一个函数的执行,并返回 expression 的值。如果 expression 被省略, 或在函数内没有 return 语句被执行,则把值 undefined 赋给调用当前函数的表达式。

return作为返回关键字,它有以下两种返回方式

1、返回函数结果

语法为:return+表达式

语句结束函数执行,返回调用函数,而且把表达式的值作为函数的结果。

function add(){

                    vara=1;

                    varb=2;

                    return a+b;

                }

                function fun(){                    console.log(add())

                }

                fun();

return 表示从被调函数返回到主调函数继续执行,返回时可附带一个返回值, 由return后面的参数指定。return通常是必要的,因为函数调用的时候计算结果通常是通过返回值带出的。

2、返回函数控制

语法为:return;

通常情况下return后面跟有表达式,但是并不是绝对的。此情况就是单纯的将控制权转交给主调函数继续执行。

在大多数情况下,为事件处理函数返回false,可以防止默认的事件行为。 例如,默认情况下点击一个a元素,页面会跳转到该元素href属性指定的页。

在js中,我们常用return false来阻止提交表单或者继续执行下面的代码。 例如下面的例子:

functiona(){

                if (Ture)

                    return false;

                };

                functionTest(){

                    a();

                    b();

                    c();

                };

即使a函数返回return false 阻止提交了,但是不影响 b()以及 c()函数的执行。在Test()函数里调用a()函数,那么 return false 对于Test()函数来说,只是相当于返回值,而不能阻止Test()函数执行。

3.简述JS中的event delegate

事件处理程序可以为现代web应用程序提供交互能力,因此许多开发人员会向页面中添加大量的处理程序。

但是在JavaScript中,添加到页面中的事件处理程序的数量会直接影响页面的整体运行性能。 

1.每个函数都是对象,都会占用内存。

2.事先指定所有的事件处理程序会导致DOM的访问次数增加,会延迟整个页面的交互时间。 对“事件处理程序过多”问题的解决方案就是事件委托(Delegation)。--JavaScript高级程序设计

3.事件委托的基本实现方式:在DOM树中尽量高的节点添加事件处理程序,代替在其多个子节点中添加。


事件委托还有一个名字叫事件代理.

JS高程上讲:

事件委托就是利用事件冒泡,只制定一个时间处理程序,就可以管理某一类型的所有事件。


这里用取快递来解释这个现象:

有三个同事预计会在周一收到快递。为签收快递,有两种办法:

一是三个人在公司门口等快递;

二是委托给前台代为签收。

现实当中,我们大都采用委托的方案。前台收到快递后,她会判断收件人是谁,然后按照收件人的要求签收,甚至代为付款。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台也会在收到寄给新员工的快递后核实并代为签收。

这里其实还有2层意思的:

第一,现在委托前台的同事是可以代为签收的,即程序中的现有的dom节点是有事件的;

第二,新员工也是可以被前台代为签收的,即程序中新添加的dom节点也是有事件的。

1为什么要用事件委托

在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能, 因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多, 就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;

每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率越大,100个li就要占用100个内存空间。 如果要用事件委托,就会将所有的操作放到js程序里面,只对它的父级(如果只有一个父级)这一个对象进行操作, 与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;

2事件委托的原理

事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?

就是事件从最深的节点开始,然后逐步向上传播事件,

举个例子:

页面上有这么一个节点树,div>ul>li>a;比如给最里面的a加一个click点击事件, 那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div, 有这样一个机制,那么我们给最外面的div加点击事件,那么里面的ul,li,a做点击事件的时候, 都会冒泡到最外层的div上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。

实例1、

实现功能是点击li,弹出123

我们看看有多少次的dom操作,首先要找到ul,然后遍历li,然后点击li的时候,又要找一次目标的li的位置,才能执行最后的操作,每次点击都要找一次li;

这里用父级ul做事件处理,当li被点击时,由于冒泡原理,事件就会冒泡到ul上,因为ul上有点击事件,所以事件就会触发,当然,这里当点击ul的时候,也是会触发的.

3 事件冒泡及捕获

DOM2.0模型将事件处理流程分为三个阶段:

一、事件捕获阶段,

二、事件目标阶段,

三、事件起泡阶段。

如图:


事件捕获:

当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,

随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。

在这个过程中,事件相应的监听函数是不会被触发的。

事件目标:

当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。

事件起泡:

从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被触发。


4事件委托的优点

通过刚才的对比介绍,大家应该能够体会到使用事件委托对于web应用程序带来的几个优点:

1.管理的函数变少了。不需要为每个元素都添加监听函数。对于同一个父节点下面类似的子元素,可以通过委托给父元素的监听函数来处理事件。

2.可以方便地动态添加和修改元素,不需要因为元素的改动而修改事件绑定。

3.JavaScript和DOM节点之间的关联变少了,这样也就减少了因循环引用而带来的内存泄漏发生的概率。

14.如何阻止事件冒泡和默认事件?

事件是监听在某个DOM元素上的,但是js的DOM事件有捕获和冒泡的机制,所以事件处理不是我们想的那样简单。

由于存在捕获和冒泡,所以事件的触发元素(目标源)不一定是当前的监听元素。于是就有一些问题

先来了解一下事件流

DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根节点之间按特定的顺序传播,

路径所经过的节点都会收到该事件,这个传播过程可称为DOM事件流。

简单理解为事件在页面的DOM节点之间传播的顺序,分为三个过程:事件捕获阶段 --> 事件目标阶段 --> 事件冒泡阶段

 

事件捕获:就是页面最外层的节点先接收事件,然后向内层元素逐级传播,比如从window ->document->html->body->div

事件冒泡:和捕获恰恰相反,让最内层先接受事件,然后向外层传播

事件目标阶段: target,不管是在传播阶段还是冒泡阶段,都必然经历目标阶段,就是对dom节点的事件进行处理

 

默认行为

浏览器的一些默认的行为。例如:点击超链接跳转,点击右键会弹出菜单,滑动滚轮控制滚动条

需要先了解一些关键点:1.event事件对象 2.目标源:target 3.当前目标源:currentTarget 4.元素element

 

1.事件对象

event对象代表事件的状态,比如事件在其发生的元素,键盘按键的状态,鼠标位置等。event对象只会在事件发生过程中存在。在触发的事件函数里,

我们会接收一个event对象,通过该对象去了解一些参数,比如要知道事件发生在谁身上,通过event的属性target来获取,方法是event.target。

 

2.target和currentTarget

target在事件流的目标阶段;currentTarget在事件流的捕获,目标及冒泡阶段。只有当事件流处在目标阶段的时候,两个的指向才是一样的,

而当处于捕获和冒泡阶段的时候,target指向被单击的对象而currentTarget指向当前事件活动的对象(一般为父级)。

<div id="outer" style="background:#fbb94a">

点击外面

<p id="inner" style="background:#5fc0cd">点击里面</p>

<br>

</div>

 

<script type="text/javascript">

function G(id){

return document.getElementById(id);

}

function addEvent(obj, ev, handler){

if(window.attachEvent){

obj.attachEvent("on" + ev, handler);

}else if(window.addEventListener){

obj.addEventListener(ev, handler, false);

}

}

function test(e){

console.log("e.target.tagName : " + e.target.tagName + "\n e.currentTarget.tagName : " + e.currentTarget.tagName);

}

var outer = G("outer");

var inner = G("inner");

//addEvent(inner, "click", test);

addEvent(outer, "click", test);

</script>

 

3.element对象

element对象表示html元素,可以拥有的类型为元素节点,文本节点,属性节点等

 

事件冒泡

在一个对象上触发某类事件(比如点击事件),如果此对象定义了此事件的处理程序,

那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,

从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。(demo)</p>

简单的说,就是我鼠标点击一个元素上,这个事件会在这个元素所有祖先元素中触发,一直冒泡到dom最上层

 

事件冒泡有什么用?

想象一下现在我们有一个10列、100行的HTML表格,你希望在用户点击表格中的某一单元格的时候做点什么。

比如说我有一次就需要让表格中的每一个单元格在被点击的时候变成可编辑状态。如果把事件处理器加到这1000个单元格会产生一个很大的性能问题,

并且有可能导致内存泄露甚至是浏览器的崩溃。相反地,使用事件代理的话,

你只需要把一个事件处理器添加到table元素上就可以了,这个函数可以把点击事件给截下来,并且判断出是哪个单元格被点击了。

 

 

如何阻止冒泡

stopPropagation()

<script>

var html = document.documentElement;

var body = document.body;

var div = body.querySelector('div');

var ul = body.querySelector('ul');

var li = body.querySelector('li');

 

//下面这种方法就是事件流的实现方式

//事件名称,点击事件,事件处理函数。true是捕获阶段发生,false是冒泡阶段发生

ul.addEventListener('click',callback,true);//2

li.addEventListener('click',callback,true);//3

div.addEventListener('click',callbackDiv,true);

 

// div.addEventListener('click',callbackDiv2,false);

body.addEventListener('click',callback,false);//4

html.addEventListener('click',callback,false);//5

//event代表事件状态,比如触发event对象的元素,鼠标位置,按键等

//event只在事件发生过程中有效

function callback(event) {

var target = event.currentTarget;

console.log(target.tagName);

}

function callbackDiv(event) {

event.stopPropagation();

console.log('div callback')

}

 

 

2.return false

javascript的return false只会阻止默认行为,而是用jQuery的话则既阻止默认行为又防止对象冒泡。

 

如何阻止默认事件

可以使用preventDefault()方法,直接使用event对象调用即可



返回列表 返回列表
评论

    分享到