添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

js常见问题总结与分析 #18

@willson-wang

Description

  1. 去掉数值的小数部分
  2. console.log(parseInt(10.23));
    console.log(~~10.23);
    console.log(10.23 >> 0);
    console.log(10.23 | 0);
    
  3. 数组最大值、最小值(不包含引用类型的值)
  4. // 第一种方法
    var maxArr = function (arr){
    	return Math.max.apply(null, arr);
    var minArr = function (arr){
    	return Math.min.apply(null, arr);
    // 第二种方法
    arr.sort(function(a,b){return a - b;});//小到大
    console.log(arr[arr.length - 1])//最大值
    console.log(arr[0])//最小值
    
  5. 获取随机色
  6. var getRandomColor = function (){
    	return '#'+Math.random().toString(16).substr(2,6);
    
  7. 深拷贝(简单深拷贝)
  8. var deepCopy = function (obj){
            //注意函数不能使用该方法进行深拷贝,因为stringify方法无法对函数进行转换
    	return JSON.parse(JSON.stringify(obj));
    
    var util = (function (){
    	var classtype;
    	var init = function (){
    		classtype = {};
    		"Boolean Number String Function Array Date RegExp Object Error".split(" ").forEach(function (item, index){
    				classtype["[object " + item + "]"] = item.toLowerCase();
    	 return {
    	 		checkType: function (obj){
    	 			 if(!classtype){
    	 			 		 init();
    	 			 if(obj == null){
    				 		return obj + "";
    	 			 return typeof obj === "object" || typeof obj === "function" ? classtype[Object.prototype.toString.call(obj)] || "object" : typeof obj;
    })();
    
    // 去两边空格
    function trim(str) {
    	return str.replace(/(^\s+)|(\s+$)/g, "");
    // 去所有空格
    function removeAllSpace(str) {
    	return str.replace(/\s+/g, "");
    
  9. 替换对象内某个key对应的值
  10. 常规方法是遍历整个对象,然后对对象的某个key对应的value进行更改,现在使用JSON.stringify方法,先将对象转化成字符串,然后了利用正则来进行转化
    var a = {
        name: 'jack',
        isRequired: true
    JSON.parse(JSON.stringify(a).replace(/true/g, 1));
    当对象内需要替换的属性值相同的较多时,而只需要替换某一个key对应的value,则上面的方法就不适用了
    var b = {
        name: 'jack',
        isRequired: true,
        isShow: true
    var str = JSON.stringify(b, (key, value) => {
      if ( key === 'isRequired') {
         return value ? 1 : 0;
      return value;
    JSON.parse(str);
    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
    
  11. 设置日期的最大值与最小值
  12. 一般在使用日历插件的时候,需要设置最大日期与最小日期
    最小日期一般很好获取,要么是个定值要么是当前值
    const START_END_TIME = 7;
    获取YYYY-MM-DD的日期格式
    utilFormatDate(date) {
        const year = date.getFullYear();
        let month = date.getMonth() + 1;
        let day = date.getDate();
        let fixMonth = month >= 10 ? month : '0' + month;
        let fixDay = day >= 10 ? day : '0' + day;
        let newDate = `${year}-${fixMonth}-${fixDay}`;
        return newDate;
    getStartAndEndDate() {
        const date = new Date();
        const startDate = this.utilFormatDate(date);
        // 设置相隔START_END_TIME天数,如7获取7天后的月日,-1获取昨天的月日等等
        date.setDate(date.getDate() + START_END_TIME)
        const endDate = this.utilFormatDate(date);
        console.log(startDate, endDate);
        return {
            startDate,
            endDate
    const {startDate, endDate} = this.getStartAndEndDate();
    

    focus/blur与focusin/focusout的区别与联系

  13. focus/blur不冒泡,focusin/focusout冒泡
  14. focus/blur兼容性好,focusin/focusout在除FireFox外的浏览器下都保持良好兼容性,如需使用事件托管,可考虑在FireFox下使用事件捕获elem.addEventListener('focus', handler, true)
  15. 可获得焦点的元素:
  16. window
  17. 链接被点击或键盘操作
  18. 表单空间被点击或键盘操作
  19. 设置tabindex属性的元素被点击或键盘操作
  20. mouseover/mouseout与mouseenter/mouseleave的区别与联系

  21. mouseover/mouseout是标准事件,所有浏览器都支持;mouseenter/mouseleave是IE5.5引入的特有事件后来被DOM3标准采纳,现代标准浏览器也支持
  22. mouseover/mouseout是冒泡事件;mouseenter/mouseleave不冒泡。需要为多个元素监听鼠标移入/出事件时,推荐mouseover/mouseout托管,提高性能标准事件模型中event.target表示发生移入/出的元素,vent.relatedTarget对应移出/如元素;在老IE中event.srcElement表示发生移入/出的元素,event.toElement表示移出的目标元素,event.fromElement表示移入时的来源元素
  23. cookie及其操作

  24. cookie是web浏览器存储的少量数据,最早设计为服务器端使用,作为HTTP协议的扩展实现。cookie数据会自动在浏览器和服务器之间传输。
  25. 通过读写cookie检测是否支持
  26. cookie属性有名,值,max-age,path, domain,secure;
  27. cookie默认有效期为浏览器会话,一旦用户关闭浏览器,数据就丢失,通过设置max-age=seconds属性告诉浏览器cookie有效期
  28. cookie作用域通过文档源和文档路径来确定,通过path和domain进行配置,web页面同目录或子目录文档都可访问
  29. 通过cookie保存数据的方法为:为document.cookie设置一个符合目标的字符串如下
  30. 读取document.cookie获得'; '分隔的字符串,key=value,解析得到结果
  31. 都会在浏览器端保存,有大小限制,同源限制
  32. cookie会在请求时发送到服务器,作为会话标识,服务器可修改cookie;web storage不会发送到服务器
  33. cookie有path概念,子路径可以访问父路径cookie,父路径不能访问子路径cookie
  34. 有效期:cookie在设置的有效期内有效,默认为浏览器关闭;sessionStorage在窗口关闭前有效,localStorage长期有效,直到用户删除
  35. 共享:sessionStorage不能共享,localStorage在同源文档之间共享,cookie在同源且符合path规则的文档之间共享
  36. localStorage的修改会促发其他文档窗口的update事件
  37. cookie有secure属性要求HTTPS传输
  38. 浏览器不能保存超过300个cookie,单个服务器不能超过20个,每个cookie不能超过4k。web storage大小支持能达到5M
  39. storage与cookie的读写操作方法不一样
  40. javascript跨域通信

  41. 同源:两个文档同源需满足
  42. 跨域通信:js进行DOM操作、通信时如果目标与当前窗口不满足同源条件,浏览器为了安全会阻止跨域操作。
  43. 跨域通信通常有以下方法
  44. 如果是log之类的简单单项通信,新建,<script>,,<iframe>元素,通过src,href属性设
    置为目标url。实现跨域请求
  45. 如果请求json数据,使用<script>进行jsonp请求
  46. 现代浏览器中多窗口通信使用HTML5规范的targetWindow.postMessage(data, origin);其中data是需要发送的对象,origin是目标窗口的origin。window.addEventListener('message', handler, false);handler的event.data是postMessage发送来的数据,event.origin是发送窗口的origin,event.source是发送消息的窗口引用
  47. 内部服务器代理请求跨域url,然后返回数据(nginx代理跨域、nodejs中间件代理跨域)
  48. 跨域请求数据,现代浏览器可使用HTML5规范的CORS功能,只要目标服务器返回HTTP头部**Access-Control-Allow-Origin: ***即可像普通ajax一样访问跨域资源
  49. // 传参并指定回调执行函数为onBack script.src = 'http://www.....:8080/login?user=admin&callback=onBack'; document.head.appendChild(script); // 回调执行函数 function onBack(res) { alert(JSON.stringify(res)); document.domain + iframe跨域 此方案仅限主域相同,子域不同的跨域应用场景 1.)父窗口:(http://www.domain.com/a.html) <iframe id="iframe" src="http://child.domain.com/b.html"></iframe> <script> document.domain = 'domain.com'; var user = 'admin'; </script> 2.)子窗口:(http://child.domain.com/b.html) document.domain = 'domain.com'; // 获取父窗口中变量 alert('get js data from parent ---> ' + window.parent.user);

    什么闭包,闭包有什么用

  50. 闭包就是函数,一个能够读取其他函数内部变量的函数。
  51. 闭包作用域链通常包括三个部分:
  52. 函数本身作用域。
  53. 闭包定义时的作用域。
  54. 全局作用域。
  55. 闭包的特性
  56. 函数内再嵌套函数
  57. 内部函数可以引用外层的参数和变量
  58. 参数和变量不会被垃圾回收机制回收
  59. 闭包的理解
  60. 使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念;闭包 的最大用处有两个,一个是可以读取函数内部的变量,让这些变量始终保持在内存中,另一个用处,是封装对象的私有属性和私有方法,好处:能够实现封装和缓存等;坏处:就是消耗内存、不正当使用会造成内存溢出的问题
  61. 使用闭包的注意点,由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露,解决方法是,在退出函数之前,将不使用的局部变量全部删除
  62. 如果都是数值型并且数值相等,他们相等, -0等于0
  63. 如果他们都是字符串并且在相同位置包含相同的16位值,那它们相等;
  64. 如果在长度或者内容上不等,它们不相等;两个字符串显示结果相同但是编码不同==和===都认为他们不相等
  65. 如果他们指向相同对象、数组、函数,它们相等;如果指向不同对象,他们不相等
  66. ==运算符判断相等的流程是怎样的

  67. 如果两个值类型相同,按照===比较方法进行比较
  68. 如果类型不同,使用如下规则进行比较
  69. 如果其中一个值是null,另一个是undefined,它们相等
  70. 如果一个值是数字另一个是字符串,将字符串转换为数字进行比较
  71. 如果有布尔类型,将true转换为1,false转换为0,然后用==规则继续比较
  72. 如果一个值是对象,另一个是数字或字符串,将对象转换为原始值然后用==规则继续比较
    其他所有情况都认为不相等
  73. <,>,<=,>=的比较规则
    所有比较运算符都支持任意类型,但是比较只支持数字和字符串,所以需要执行必要的转换然后进行比较,转换规则如下:

  74. 如果操作数是对象,转换为原始值:如果valueOf方法返回原始值,则使用这个值,否则使用toString方法的结果,如果转换失败则报错
    经过必要的对象到原始值的转换后,如果两个操作数都是字符串,按照字母顺序进行比较(他们的16位unicode值的大小)
    否则,如果有一个操作数不是字符串,将两个操作数转换为数字进行比较
  75. 函数内部arguments变量有哪些特性,有哪些属性,如何将它转换为数组

  76. arguments所有函数中都包含的一个局部变量,是一个类数组对象,对应函数调用时的实参。如果函数定义同名参数会在调用时覆盖默认对象
  77. arguments[index]分别对应函数调用时的实参,并且通过arguments修改实参时会同时修改实参
  78. arguments.length为实参的个数(Function.length表示形参长度)
  79. arguments.callee为当前正在执行的函数本身,使用这个属性进行递归调用时需注意this的变化
  80. arguments.caller为调用当前函数的函数(已被遗弃)
  81. 转换为数组:var args = Array.prototype.slice.call(arguments, 0);
  82. iframe有那些缺点?

  83. iframe会阻塞主页面的Onload事件
  84. 搜索引擎的检索程序无法解读这种页面,不利于SEO
  85. iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载
  86. 使用iframe之前需要考虑这两个缺点。如果需要使用iframe,最好是通过javascript动态给iframe添加src属性值,这样可以绕开以上两个问题
  87. This指向的理解

  88. 事件函数内的this
  89. 对象方法内的this
  90. new构造函数时构造函数内的this
  91. 普通函数调用时,函数内的this
  92. call,apply调用时,函数内的this
  93. 箭头函数内的this
  94. Ajax原理
    Ajax的原理简单来说是在用户和服务器之间加了—个中间层(AJAX引擎),通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用javascript来操作DOM而更新页面。使用户操作与服务器响应异步化。这其中最关键的一步就是从服务器获得请求数据

    var xhr = null;
        xhr = new XMLHttpRequest()
        // 2. 连接服务器
        xhr.open('get', url, true)
        // 3. 发送请求
        xhr.send(null);
        // 4. 接受请求
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
                if(xhr.status == 200){
                    success(xhr.responseText);
                } else { // fail
                    fail && fail(xhr.status);
    

    异步加载JS的方式有哪些?

  95. defer,只支持IE
  96. async:
  97. 创建script,插入到DOM中,加载完毕后callBack
  98. defer和async的区别

  99. defer并行加载js文件,会按照页面上script标签的顺序执行
  100. async并行加载js文件,下载完成立即执行,不会按照页面上script标签的顺序执行
  101. 说说你对AMD和CommonJs的理解
    CommonJS是服务器端模块的规范,Node.js采用了这个规范。CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数
    AMD推荐的风格通过返回一个对象做为模块对象,CommonJS的风格通过对module.exports或exports的属性赋值来达到暴露模块对象的目的

    严格模式常见的限制

  102. 变量必须声明后再使用
  103. 函数的参数不能有同名属性,否则报错
  104. 不能使用with语句
  105. 禁止this指向全局对象
  106. addEventListener 兼容ie9+,所以如果项目是在ie9+以上浏览器内运行,直接就可以用,不用考虑兼容性

    判断js内某个字符串全是数字

  107. 使用isNaN;
  108. 使用正则/\d+/g
  109. 如何获取浏览器滚动条高度

  110. 在ie、firefox、chrome下都是使用document.documentElement.scrollTop 而不是document.body.scrollTop,jquery下是使用$(window).scrollTop
  111. forEach,map, forin不能遍历dom合集,要遍历dom集合需要使用for or 将dom集合转换成数组

    var oLis = document.getElmentsByTagName('li');
    // 使用for循环遍历
    for (var i = 0; i < oLis.length; i++) {}
    // 将合集转换成数组,然后在遍历
    var arrOlis = Array.prototype.slice.call(oLis);
    var arrOlis = Array.from(oLis);
    var arrOlis = [...oLis];
    

    Object.assign

  112. 合并or拷贝对象,并不是深拷贝,是披着深拷贝外衣的浅拷贝。最多也是Object.assign会深拷贝第一层的值,对于第一层的值都是深拷贝,而到第二层的时候就是复制引用。类似的情况还有,slice方法和concat方法等。
  113. addClass removeClass hasClass toggleClass

    function hasClass (dom, className) {
         var reg = new RegExp('(^|\\s)' + className+ '(\\s|$)');
         return reg .test(dom.className);
    function addClass (dom, clsName) {
        if (!hasClass(dom, clsName)) {
            let classStr = dom.getAttribute('class');
            dom.className = classStr.trim() + ' ' + clsName;
    function removeClass (dom, clsName) {
        if (hasClass(dom, clsName)) {
            let classStr = dom.getAttribute('class');
            let newClassStr = classStr.replace(clsName, '');
            dom.className = newClassStr;
    function toggleClass (dom, clsName) {
        if (hasClass(dom, clsName)) {
            removeClass(dom, clsName);
        } else {
            addClass(dom, clsName);
    

    appendChild方法插入的元素怎么样去使用transition动画

    requestAnimationFrame方法可以在什么样的场景下使用

    elementsFromPoint方法的作用是什么

    apply 与 call

  114. 非常相似,不同之处在于提供参数的方式。apply 使用参数数组而不是一组参数列表。apply 可以使用数组字面量(array literal),如 fun.apply(this, ['eat', 'bananas']),或数组对象, 如 fun.apply(this, new Array('eat', 'bananas'))。
  115. 需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定为null和undefined的this值会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。
  116. 为什么ES5及以下的JS无法完美继承数组,最优的方式是什么

    throw语句

  117. throw语句用来抛出一个用户自定义的异常。当前函数的执行将被停止(throw之后的语句将不会执行),并且控制将被传递到调用堆栈中的第一个catch块。如果调用者函数中没有catch块,程序将会终止,语法为throw expression; expression可以是字符串,数字,布尔值
  118. 一般可用来捕获异常or中断循环,如forEach循环也是可以被中断的,条件是forEach遍历是放在try catch内的,因为不放在try catch语句内,直接throw是会抛出一个异常终止程序执行的
  119. try {
       throw '__break__';
    } catch (e) {
       这里的e就是throw后面的内容
    

    propertyIsEnumerable

  120. propertyIsEnumerable方法返回一个布尔值,表示指定的属性是否可枚举。
  121. forEach方法

  122. forEach方法对数组的每个元素执行一次提供的函数。返回值为undefined;即forEach() 为每个数组元素执行callback函数;不像map() 或者reduce() ,它总是返回 undefined值,并且不可链式调用,没有办法中止或者跳出 forEach 循环,除了抛出一个异常。
  123. undefined与void 运算符

  124. undefined并不是保留词(reserved word),它只是全局对象的一个属性,在低版本 IE 中能被重写,undefined 在 ES5 中已经是全局对象的一个只读(read-only)属性了,它不能被重写。但是在局部作用域中,还是可以被重写的
  125. void 运算符 对给定的表达式进行求值,然后返回 undefined。void 运算符通常只用于获取 undefined的原始值,一般使用void(0)(等同于void 0)
  126. for...in语句

  127. for...in语句以任意顺序遍历一个对象的可枚举属性(包括原型上继承的)。对于每个不同的属性,语句都会被执行,另外for in遍历不是按顺序来进行遍历的,它跟每个浏览器自身的实现有关,for in出问题会包含两个条件其一是在 IE < 9 浏览器中(又是万恶的 IE!!),其二是被枚举的对象重写了某些键,如重写了toString属性,chrome下能够正常返回,ie8则不会弹出,因为IE 8 将 toString "内定" 成了不可枚举属性(尽管已经被重写)
  128. 0.1 +0.2===0.30000000000000004的原因

  129. EcmaScrpt规范定义Number的类型遵循了IEEE754-2008中的64位浮点数规则定义的小数后的有效位数至多为52位导致计算出现精度丢失问题!所以可以使用toFixed() 方法来解决这个问题,兼容ie9+
    numObj.toFixed(digits) 方法使用定点表示法来格式化一个数,返回值为所给数值的定点数表示法的字符串形式。 digits小数点后数字的个数;介于 0 到 20 (包括)之间,实现环境可能支持更大范围。如果忽略该参数,则默认为 0。digits具体值取决于传入参数)位数字。该数值在必要时进行四舍五入,另外在必要时会用 0 来填充小数部分,以便小数部分有指定的位数。 如果数值大于 1e+21,该方法会简单调用 Number.prototype.toString()并返回一个指数记数法格式的字符串。
  130. var numObj = 12345.6789;
    numObj.toFixed();         // 返回 "12346":进行四舍五入,不包括小数部分
    numObj.toFixed(1);        // 返回 "12345.7":进行四舍五入
    numObj.toFixed(6);        // 返回 "12345.678900":用0填充
    (1.23e+20).toFixed(2);    // 返回 "123000000000000000000.00"
    

    Babel的相关知识

    Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片

    babel-preset-env 的工作方式类似 babel-preset-latest,唯一不同的就是 babel-preset-env 会根据配置的 env 只编译那些还不支持的特性。即babel-preset-env包含了babel-preset-2015,babel-preset-2016等,但不包括babel-polyfill及babel-preset-stag

    关于iframe引入页面进行打印的小结

  131. 当在父页面调用iframe页面内的打印方法时,如果iframe页面没有进行focus操作,那么打印就是打印父页面的内容,也包括ifame的内容,如果iframe页面内进行了fouse操作,那么只会打印iframe里面的内容,注意了这里打印ifame里面的内容宽高,与打印机的标签纸张大小有关,与iframe及iframe内的元素宽高无关,当iframe内的内容宽高小于打印纸张的宽高时,内容会全部打印出来,当内容的宽高大于纸张的宽高时只会打印出纸张视图内的内容,所以打印最好的方式就是显示一个元素,打印一个元素,然后删除一个元素,注意这里用setTimeout而不是setInterval,原因是setInterval会根据执行的快慢来调整执行的时机,即不一定按时间间隔来准确执行,而setTimeout会按准确的时间间隔来执行
  132. 原生js及jquery,父页面获取iframe页面的window对象,document对象,及元素的方式,iframe页面获取父页面window对象,document对象,及元素的方法

  133. 关键是先获取window对象(注意通过window点出来的直接就是iframe的window对象了,而通过先获取iframe元素的话,就需要通过元素的contentWindow属性来获取window对象),然后再通过window对象获取到document对象,然后通过document对象来获取元素
  134. js获取iframe元素的window对象 window.iframes["name名字"]  兼容chrome,ff,ie9+   
    document.getElementById("iframeid").contentWindow  or this.contentWindow
     jquery获取iframe元素的window对象  
    $("iframe")[0].contentWindow
    js获取iframe的document对象   window.iframes["name名字"].document   or document.getElementById("iframeid").contentWindow.document  or  this.contentWindow.document
    jquery获取iframe的document对象  $("iframe")[0].contentWindow.document  or $(this.contentWindow.document)
    js获取获取iframe的元素   
    window.iframes["name名字"].document.getElementById("test")
    jquery获取获取iframe的元素   $($("iframe")[0].document).find("#test")  or $(this.contentWindow.document).find(".ui-label-content-body")
    js iframe获取父页面的window对象
    window.parent  or parent
    jquery获取iframe元素的window对象  
    $(window.parent) or $(parent)
    js获取iframe的document对象   
    window.parent.document
    jquery获取iframe的document对象  
    $(window.parent.document) or $(parent.document)
     js获取获取iframe的元素   
    window.parent.document.getElementById("test") or parent.document.getElementById("test")
     jquery获取获取iframe的元素   $("#test", parent.document)  or $(window.parent.document).find("#test"); or $(parent.document).find("#test");
    

    当动态创建多个iframe时,怎么去保证当前iframe里面的值就是创建当前iframe时主页面中的值

  135. 试了数组的方式,也试了在iframe元素上加属性的方式,效果都是不特别好,可能会出现iframe内的值,不是创建时需要取的值,解决方法就是在主页面创建一个key-value的对象,然后在iframe内通过key来获取值。这样可以保证每个iframe内取值时,取得就是当前iframe创建时候的值,不会出现错误,另外需要注意的是,iframe内是无法获取到当前iframe元素上的属性值的,唯一的方法就是在父页面内定义一个方法,然后在iframe页面内进行调用
  136. 浏览器输出的对象的key值不是按后台返回的key值顺序来显示

  137. js里面在定义对象时,对象的key是没有顺序的,但是当输出的时候,浏览器就好根据key的ascii来进行从小到大的排序,所以如果输出的内容不需要进行排序的话,可以使用对象直接输出,如果需要对key进行排序的话,就需要使用数组包对象来进行输出,然后利用sort方法来进行排序
  138. 同名的函数与变量函数的提示在变量之后,即先找变量,找到a,然后将a赋值为undefined,然后找函数,发现函数有同名变量,然后会去覆盖同名变量a