Arguments 对象:

在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。

例如,在函数 sayHi() 中,第一个参数是 message。用 arguments[0] 也可以访问这个值,即第一个参数的值(第一个参数位于位置 0,第二个参数位于位置 1,依此类推)。

可以用于模拟函数重载:

  1. function doAdd() {
  2. if(arguments.length == 1) {
    //但只有一个参数的时候,加5
  3. alert(arguments[0] + 5);
  4. } else if(arguments.length == 2) {
    //但有两个参数的时候,这两个参数相加
  5. alert(arguments[0] + arguments[1]);
  6. }
  7. }
  8.  
  9. doAdd(10); //输出 "15"
  10. doAdd(40, 20); //输出 "60"

虽然不如重载那么好,不过已足以避开 ECMAScript 的这种限制。

eval() 函数:函数可计算某个字符串,并执行其中的的 JavaScript 代码;表示JavaScript表达式,语句或一系列语句的字符串。表达式可以包含变量以及已存在对象的属性。

在非严格的js模式下:

  1. var x = 2;
  2. console.log(eval("var x = 5; x")); //5
  3. console.log(x);            //5

在严格模式下:

  1. "use strict";
  2. var x = 2;
  3. console.log(eval("var x = 5; x"));//5
  4. console.log(x);           //2

正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部。

eval() 通常比替代方法慢,因为它必须调用 JS 解释器,而许多其他结构则由现代 JS 引擎进行优化。

箭头函数和普通函数的区别:

箭头函数属于匿名函数,匿名函数是要通过赋值语句赋值给变量,这个赋值的过程是在代码执行阶段进行的,不是在声明阶段,所以没有函数声明的提升属性。

箭头函数中的 this 和调用时的上下文无关,而是取决于定义时的上下文:

  1. function make () {
  2. return ()=>{
  3. console.log(this);
  4. }
  5. }
  6. var testFunc = make.call({name:'foo'});
  7. testFunc(); //{ name: 'foo' }
  8. testFunc.call({name:'bar'}); //{ name: 'foo' }
    //如果是普通函数的话,结果就是{ name: 'bar'}

这个例子可以看到,确实箭头函数在定义之后,this 就不会发生改变了,无论用什么样的方式调用它,this 都不会改变;但严格来说,这并不是“取决于定义时的上下文”, 因为箭头函数根本就没有绑定自己的 this,在箭头函数中调用 this 时,仅仅是简单的沿着作用域链向上寻找,找到最近的一个 this 拿来使用罢了;在普通函数中,会自动绑定上的各种局部变量,箭头函数都是十分单纯的沿着作用域链向上寻找.

当然普通函数也可以实现和箭头函数一样的效果:

  1. function make () {
  2. //保存当前作用域的this
  3. var self = this;
  4. return function () {
  5. console.log(self);
  6. }
  7. }
  8.  
  9. function make () {
  10. return function () {
  11. console.log(this);
  12. }.bind(this);
  13. //绑定当前作用域的this
  14. }
  15. var testFunc = make.call({name:'foo'});
  16. testFunc(); //{ name: 'foo' }
  17. testFunc.call({name:'bar'});//{ name: 'foo' }

JS中的冒泡流和捕获流

addEventListener第三个参数useCapture ,true时为捕获,false时为冒泡

冒泡从目标对象开始,向父级元素至window传递;捕获从window底层逐级至目标对象传递!

事件捕获
当你使用事件捕获时,父级元素先触发,子级元素后触发,即div先触发,p后触发。

事件冒泡
当你使用事件冒泡时,子级元素先触发,父级元素后触发,即p先触发,div后触发。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  8. <title>Document</title>
  9.  
  10. </head>
  11. <body>
  12. <div id="divAlert" onclick="divAlert();">
  13. <div onclick="anothor();"></div>
  14. <input type="button" id="btn" value="click">
  15. </div>
  16. </body>
  17. <script type="text/javascript">
  18. let btn = document.getElementById('btn');
  19. let divParent = document.getElementById('divAlert');
  20. const anothor = () => {
  21. alert('you click this same level');
  22. }
  23. const alertMessage = (e) => {
  24. // e.stopPropagation();
  25. alert('you click this button');
  26. }
  27. const divAlert = () => {
  28. alert('you click this div');
  29. }
  30. //divParent.addEventListener('click',divAlert,true);
  31. btn.addEventListener('click',alertMessage,false);
  32. </script>
  33. </html>

执行顺序是:

  1. alert('you click this button');
  1. alert('you click this div');
    当我们把false改成true试下:
    执行顺序:
  1. alert('you click this button');
  1. alert('you click this div');
  1. 说好的true是捕获呢,这是因为上一个div没有设置addEventListener,再试下:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  8. <title>Document</title>
  9. </head>
  10. <body>
  11. <div id="divAlert" onclick="divAlert();">
  12. <div onclick="anothor();"></div>
  13. <input type="button" id="btn" value="click">
  14. </div>
  15. </body>
  16. <script type="text/javascript">
  17. let btn = document.getElementById('btn');
  18. let divParent = document.getElementById('divAlert');
  19. const alertMessage = (e) => {
  20. //e.stopPropagation();
  21. alert('you click this button');
  22. }
  23. const divAlert = (e) => {
  24. alert('you click this div');
  25. }
  26. divParent.addEventListener('click',divAlert,true);
  27. btn.addEventListener('click',alertMessage,true);
  28. </script>
  29. </html>

执行结果是:

  1. alert('you click this div');
  1. alert('you click this button');
  1. alert('you click this div');
    刚开始的结果是没错的,div先然后子元素,但是为什么是三次呢?
    第一次:button触发了捕获事件弹出的,这时就触发了他本身的click事件但由于事件的优先级不同,所以没有再次弹出
    第二次:捕获从window底层逐级至目标对象,因为这里只要一个父级绑定了click,所以现在是button自身的click
    第三次:就是第一次时触发了div本身的click事件
  1. 但我们只想要前两个提示怎么办,把上面的注释去掉就可以了,就是第二次弹出后,强制阻止事件捕获或冒泡。
    结果当然就是我们所期望的。

这里介绍stopImmediatePropagation() 和 stopPropagation()

后者只会阻止冒泡或者是捕获。 但是前者除此之外还会阻止该元素的其他事件发生,但是后者就不会阻止其他事件的发生。

这里的逻辑比较简单就用不到。

JS中的鼠标事件:

鼠标事件是JS最经常用的事件,其中:

onmousedown:在用户按下任何鼠标时触发

onmousemove:当鼠标指针在元素内部移动时重复地触发

onmouseup:会在鼠标按键被松开时发生

我们来做个例子来看下各个事件时怎么触发的:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  8. <title>Document</title>
  9. </head>
  10. <style>
  11. * {
  12. padding: 0;
  13. margin: 0;
  14. }
  15. #dragBox {
  16. width: 400px;
  17. height: 250px;
  18. background: deepskyblue;
  19. /* 这个是关键,没有这个的话,子元素的margin:10px auto;不起作用*/
  20. overflow: hidden;
  21. position: absolute;
         /*为了一开始强行让它在页面中居中*/
  22. top: 50%;
  23. left: 50%;
  24. /* absolute居中 */
  25. /* 宽度的一半 */
  26. margin-left: -200px;
  27. /* 高度的一半 */
  28. margin-top: -125px;
  29. }
  30. .target {
  31. box-sizing: border-box;
  32. width: 50%;
  33. height: 50px;
  34. background-color: deeppink;
  35. margin: 10px auto;
  36. overflow: hidden;
  37. text-align: center;
  38. line-height: 50px;
  39. }
  40.  
  41. .target:hover {
  42. cursor: pointer;
  43. }
  44. </style>
  45.  
  46. <body>
  47. <div id="dragBox">
  48. <div class="target">
  49. 可拖动区域
  50. </div>
  51. </div>
  52. </body>
  53. </html>

接下来就是写JS了,获取class的话一般都会想到document.getElementsByClassName(''),但是这个效率感人,所以我们自己写个效果差不多的函数,但效率较高:

  1. const getByClass = (clsName, parent) => {
  2. let oParent = parent ? document.getElementById(parent) : document,
  3. eles = [],
  4. elements = oParent.getElementsByTagName('*');
  5.  
  6. for (let i = 0; i < elements.length; i++) {
  7. if (elements[i].className == clsName) {
  8. eles.push(elements[i]);
  9. }
  10. }
  11. return eles;
  12. }

接下来写鼠标拖动这个div的JS:

  1. <script>
  2. //找出className想符合的元素集可以指定父级元素的ID,速度会更快点
  3. const getByClass = (clsName, parent) => {
  4. let oParent = parent ? document.getElementById(parent) : document,
  5. eles = [],
  6. elements = oParent.getElementsByTagName('*');
  7.  
  8. for (let i = 0; i < elements.length; i++) {
  9. if (elements[i].className == clsName) {
  10. eles.push(elements[i]);
  11. }
  12. }
  13. return eles;
  14. }
  15.  
  16. function fnDown(event) {
  17. event = event || window.event;
  18. console.log(event);
  19. let dragBox = document.getElementById('dragBox'),
  20. //计算出盒子和左边框的距离,因为要设置absolute又要让他居中,
  21. //所以我设置了margin所以这边得减掉marginLeft和marginTop
  22. relativeBoxX = event.clientX - dragBox.offsetLeft - dragBox.offsetWidth/2,
  23. relativeBoxY = event.clientY - dragBox.offsetTop - dragBox.offsetHeight/2;
  24. document.onmousemove = function (event) {
  25. event = event || window.event;
  26. fnMove(event, relativeBoxX, relativeBoxY);
  27. }
  28. document.onmouseup = function(){
  29. document.onmousemove = null;
  30. document.onmouseup = null;
  31. }
  32. }
  33.  
  34. const drag = () => {
  35. let onTitle = getByClass('target', 'dragBox')[0];
  36. let dragBox = document.getElementById('dragBox');
  37. onTitle.onmousedown = fnDown;
  38. }
  39.  
  40. const fnMove = (e, Posx, Posy) => {
  41. let l = e.clientX - Posx,
  42. t = e.clientY - Posy,
  43. oDrag = document.getElementById('dragBox'),
  44. //窗口的宽度
  45. winW = document.documentElement.clientWidth || documentb.body.clientWidth,
  46. //窗口的高度
  47. winH = document.documentElement.clientHeight || document.body.clientHeight,
  48. //oDrag.offsetWidth是当前div宽度
  49. //oDrag.offsetHeight是当前div高度
  50. maxW = winW - oDrag.offsetWidth,
  51. maxH = winH - oDrag.offsetHeight;
  52. //为了不让div上下左右边框超过屏幕,提高用户体验
  53.  
  54. //跟上面一样,这边因为div是向右偏移
  55. //所以要加上marginLeft和marginTop
  56. if (l < 0 + dragBox.offsetWidth/2) {
  57. l = 0 + dragBox.offsetWidth/2;
  58. }
  59. else if (l > maxW + dragBox.offsetWidth/2) {
  60. l = maxW + dragBox.offsetWidth/2;
  61. }
  62. if (t < 0 + dragBox.offsetHeight/2) {
  63. t = 0 + dragBox.offsetHeight/2;
  64. } else if (t > maxH + dragBox.offsetHeight/2) {
  65. t = maxH + dragBox.offsetHeight/2;
  66. }
  67. console.log(`left${l}top${t}`);
  68.  
  69. oDrag.style.left = l + 'px';
  70. oDrag.style.top = t + 'px';
  71. }
  72. window.onload = drag;
  73. </script>

现在运行,拖动可拖动区域就可以满屏幕拖动了,上面的代码有注释,但我还是要讲两个较难理解的点:

在fnDown()中relativeBoxX = event.clientX - dragBox.offsetLeft - dragBox.offsetWidth/2,event.clientX是鼠标点击下位置与左边窗口的距离,dragBox.offsetLeft是当前div与左边窗口的距离,dragBox.offsetWidth/2是margin-left:-200px,也就是当前div宽度的一半是我为了让div一开始强制在页面居中,可以在纸上画一画,下面给出我画的图,看下应该就可以理解了。

  1. 还有比上面简单的重点:但我们用鼠标滑到窗口边缘时,我们的div的边缘跟着跑出边缘,这样有点难看,所以可以优化下,
  1. let l = e.clientX - Posx,
  2. t = e.clientY - Posy,
  3. oDrag = document.getElementById('dragBox'),
  4. //窗口的宽度
  5. winW = document.documentElement.clientWidth || documentb.body.clientWidth,
  6. //窗口的高度
  7. winH = document.documentElement.clientHeight || document.body.clientHeight,
  8. //oDrag.offsetWidth是当前div宽度
  9. //oDrag.offsetHeight是当前div高度
  10. maxW = winW - oDrag.offsetWidth,
  11. maxH = winH - oDrag.offsetHeight;
  12. //为了不让div上下左右边框超过屏幕,提高用户体验
  13.  
  14. //跟上面一样,这边因为div是向右偏移
  15. //所以要加上marginLeft和marginTop
  16. if (l < 0 + dragBox.offsetWidth/2) {
  17. l = 0 + dragBox.offsetWidth/2;
  18. }
  19. else if (l > maxW + dragBox.offsetWidth/2) {
  20. l = maxW + dragBox.offsetWidth/2;
  21. }
  22. if (t < 0 + dragBox.offsetHeight/2) {
  23. t = 0 + dragBox.offsetHeight/2;
  24. } else if (t > maxH + dragBox.offsetHeight/2) {
  25. t = maxH + dragBox.offsetHeight/2;
  26. }
  1.  

因为我们的l=e.clientX - Posx,所以当鼠标移到窗口左边边缘时,肯定是负数的,left也跟着负数,这是只要判断为负数时,变为0,div到窗口左边的距离就是下图所示:

然后上下边缘意思都一样了,最后记得在fnDown()中添加

  1. document.onmouseup = function(){
  2. document.onmousemove = null;
  3. document.onmouseup = null;
  4. }
    这样鼠标放开就没有再触发onmousemove事件了,最后我想说的是,其实这个并不难,只是开头为了让它强制居中,加了margin-left,margin-top,导致每个地方都要加
    dragBox.offsetWidth/2,
  1. dragBox.offsetHeight/2
  2.  
  3. 其实把css中的margin删掉,js中所有
  1. dragBox.offsetWidth/2 dragBox.offsetHeight/2都可以删掉,就变得非常简单易懂。
  1. 最后记一点笔记,下面是常用的内置属性:
  1. 网页可见区域宽: document.documentElement.clientWidth;
  2. 网页可见区域高: document.documentElement.clientHeight;
  3. 网页正文全文宽: document.documentElement.scrollWidth;
  4. 网页正文全文高: document.documentElement.scrollHeight;
  5. 网页被卷去的高(ff):document.body.scrollTop;
  6. 网页被卷去的高(ie): document.documentElement.scrollTop;
  7. 网页被卷去的左:document.body.scrollLeft;
  8. 网页正文部分上:window.screenTop;
  9. 网页正文部分左:window.screenLeft;
  10. 某个元素的宽度:obj.offsetWidth;
  11. 某个元素的高度:obj.offsetHeight;
  12. 某个元素的上边界到body最顶部的距离:obj.offsetTop;(在元素的包含元素不含滚动条的情况下)
  13. 某个元素的左边界到body最左边的距离:obj.offsetLeft;(在元素的包含元素不含滚动条的情况下)
  14. 返回当前元素的上边界到它的包含元素的上边界的偏移量:obj.offsetTop(在元素的包含元素含滚动条的情况下)
  15. 返回当前元素的左边界到它的包含元素的左边界的偏移量:obj.offsetLeft(在元素的包含元素含滚动条的情况下)

深入浅出原生JS:One的更多相关文章

  1. 读书笔记: 深入浅出node.js

    >> 深入浅出node.js node.js是c++编写的js运行环境 浏览器: 渲染引擎 + js引擎 后端的js运行环境 node.js用google v8引擎,同时提供很多系统级的A ...

  2. 深入浅出Node.js(上)

    (一):什么是Node.js Node.js从2009年诞生至今,已经发展了两年有余,其成长的速度有目共睹.从在github的访问量超过Rails,到去年底Node.jsS创始人Ryan Dalh加盟 ...

  3. 深入浅出node.js游戏服务器开发1——基础架构与框架介绍

    2013年04月19日 14:09:37 MJiao 阅读数:4614   深入浅出node.js游戏服务器开发1——基础架构与框架介绍   游戏服务器概述 没开发过游戏的人会觉得游戏服务器是很神秘的 ...

  4. 原生JS封装Ajax插件(同域&&jsonp跨域)

    抛出一个问题,其实所谓的熟悉原生JS,怎样的程度才是熟悉呢? 最近都在做原生JS熟悉的练习... 用原生Js封装了一个Ajax插件,引入一般的项目,传传数据,感觉还是可行的...简单说说思路,如有不正 ...

  5. 常用原生JS方法总结(兼容性写法)

    经常会用到原生JS来写前端...但是原生JS的一些方法在适应各个浏览器的时候写法有的也不怎么一样的... 今天下班有点累... 就来总结一下简单的东西吧…… 备注:一下的方法都是包裹在一个EventU ...

  6. 原生JS实现"旋转木马"效果的图片轮播插件

    一.写在最前面 最近都忙一些杂七杂八的事情,复习软考.研读经典...好像都好久没写过博客了... 我自己写过三个图片轮播,一个是简单的原生JS实现的,没有什么动画效果的,一个是结合JQuery实现的, ...

  7. 再谈React.js实现原生js拖拽效果

    前几天写的那个拖拽,自己留下的疑问...这次在热心博友的提示下又修正了一些小小的bug,也加了拖拽的边缘检测部分...就再聊聊拖拽吧 一.不要直接操作dom元素 react中使用了虚拟dom的概念,目 ...

  8. React.js实现原生js拖拽效果及思考

    一.起因&思路 不知不觉,已经好几天没写博客了...近来除了研究React,还做了公司官网... 一直想写一个原生js拖拽效果,又加上近来学react学得比较嗨.所以就用react来实现这个拖 ...

  9. 原生JS实现全屏切换以及导航栏滑动隐藏及显示——重构前

    思路分析: 向后滚动鼠标滚轮,页面向下全屏切换:向前滚动滚轮,页面向上全屏切换.切换过程为动画效果. 第一屏时,导航栏固定在页面顶部,切换到第二屏时,导航条向左滑动隐藏.切换回第一屏时,导航栏向右滑动 ...

随机推荐

  1. Prometheus 详解

    Prometheus 章节 1.Prometheus 简介 2.Prometheus 安装与配置 3.Exporter 4.Pushgateway 5.本地存储和远程存储 6.高可用方案 7.报警插件 ...

  2. qrcode-使用

    安装 composer require endroid/qrcode namespace App\Http\Controllers\Admin; use Endroid\QrCode\QrCode; ...

  3. Python集成开发环境Pycharm+Git+Gitee(码云)

    ********************************************************************* 本文主要介绍集成开发环境的配置过程,方便多人协作办公.代码版 ...

  4. 打开myeclipse出现这个错是为什么

  5. JPA 继承关系实现的三种方式

    single table 一张表保存所有类型 join 扩展属性保存在子表中 TABLE_PER_CLASS 每个类型一张表

  6. yum update过程中失败后再次执行出现“xxxx is a duplicate with xxxx”问题

    问题现象: 解决办法: 利用yum-uitls中的工具package-cleanup指令,使用方法见下图,具体可通过man package-cleanup查询 列出重复的rpm包        pac ...

  7. Neo4j parameter

    Neo4j browser: $ :help param Set a parameter Set a parameter to be sent with queries. The :param nam ...

  8. 求背景图片左边到#box盒子左边框外侧的距离

    box{ width: 100px; height: 200px; background: pink; padding: 100px; border: 80px solid; background-i ...

  9. python os模块用法

    import os   #os主要做路径管理import glob  #glob主要做搜索查询匹配import sys inputpath = r"C:\Users\Administrato ...

  10. Redis中存储对象区别

    1.最常用的是String结构,key和value都是字符串类型: 2.哈希:比较是用于对对象的操作: 3.List:按照插入数据顺序保存,value是可以重复的,底层是双向链表: 4.集合:是Str ...