$.extend 的一个小问题


Posted in Javascript onJune 18, 2015

最近一直在搞移动端,也由于自己对jQuery比较熟悉,再加上Zepto提供了跟jQuery一样的API,所以就选择了Zepto作为开发框架。

由于是移动端开发,所以也应用了一些ES5新增的API,比如forEach,下面就是我写的代码的一些示例:

list.forEach(function(v) {
 return !!v;
})

我天真的以为forEach就跟jQuery的each一样,只要我的返回值为false,它就会中断循环,于是,类似这样的遍历代码写了不少(真的是懒得为每个遍历去声明变量啊)

写了一段时间之后我突然发现,forEach的回调函数并不能中断循环,于是,我便在Array.prototype上面挂了个函数,然后replaceAll,完美。

Array.prototype.foreach = function(fn) {
  var i = 0, len = this.length;

  for (; i < len; ++i) {

    if (fn(this[i], i) === false) {
     break;
    }
   }
 };

直到有一天,我想做点优化,考虑到客户端需要保存的json过大(没骗你,最大可以去到20M),stringify的时候太过耗时,会阻塞UI,所以我就用Worker在后台开个线程,专门用来stringify这个json,类似于这样子:

addEventListener("message", function(e) {

  var data = e.data;

  data = JSON.stringify(data);

  postMessage(data);

}, false);

posMesage:

worker.postMessage(data)

但是控制台却输出了以下的错误信息:

Uncaught DataCloneError: Failed to execute 'postMessage' on 'Worker': An object could not be cloned.

坑爹,这天杀的为什么连个json都复制不了,于是乎,我开始寻找原因,让我发现了我的json里面有这个东西:

天啊,这是什么鬼,这个foreach为什么跑进来了,我看了一下编辑器里面的$.extend(true, {}, obj)正在那里瑟瑟发抖,我不禁怀疑,不会是你丫的在作怪吧。于是乎,我查看了一下$.extend的源码:

function extend(target, source, deep) {
  for (key in source)
   if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
    if (isPlainObject(source[key]) && !isPlainObject(target[key]))
     target[key] = {}
    if (isArray(source[key]) && !isArray(target[key]))
     target[key] = []
    extend(target[key], source[key], deep)
   }
   else if (source[key] !== undefined) target[key] = source[key]
 }

 // Copy all but undefined properties from one or more
 // objects to the `target` object.
 $.extend = function(target){
  var deep, args = slice.call(arguments, 1)
  if (typeof target == 'boolean') {
   deep = target
   target = args.shift()
  }
  args.forEach(function(arg){ extend(target, arg, deep) })
  return target
 }

我的天啊,还真是这货在作怪啊,遍历数组用for...in..也就算了,但是 else if (source[key] !== undefined) target[key] = source[key] 这里的条件能不能严肃点啊,加个hasOwnProperty检查一下不会浪费多少时间吧。泪流满面

被Zepto坑了之后,我立马去找jQuery投诉,希望它能安慰我一下,没想到:

jQuery.extend = jQuery.fn.extend = function() {
  var options, name, src, copy, copyIsArray, clone,
    target = arguments[0] || {},
    i = 1,
    length = arguments.length,
    deep = false;

  // Handle a deep copy situation
  if ( typeof target === "boolean" ) {
    deep = target;
    target = arguments[1] || {};
    // skip the boolean and the target
    i = 2;
  }

  // Handle case when target is a string or something (possible in deep copy)
  if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
    target = {};
  }

  // extend jQuery itself if only one argument is passed
  if ( length === i ) {
    target = this;
    --i;
  }

  for ( ; i < length; i++ ) {
    // Only deal with non-null/undefined values
    if ( (options = arguments[ i ]) != null ) {
      // Extend the base object
      for ( name in options ) {
        src = target[ name ];
        copy = options[ name ];

        // Prevent never-ending loop
        if ( target === copy ) {
          continue;
        }

        // Recurse if we're merging plain objects or arrays
        if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
          if ( copyIsArray ) {
            copyIsArray = false;
            clone = src && jQuery.isArray(src) ? src : [];

          } else {
            clone = src && jQuery.isPlainObject(src) ? src : {};
          }

          // Never move original objects, clone them
          target[ name ] = jQuery.extend( deep, clone, copy );

        // Don't bring in undefined values
        } else if ( copy !== undefined ) {
          target[ name ] = copy;
        }
      }
    }
  }

  // Return the modified object
  return target;
};

这货也是 else if ( copy !== undefined ) {target[ name ] = copy;} 就交代了,我的亲娘啊。

最后迫不得已,只得自己写了一个。

总结:当你要使用$.extend的时候,不要轻易在Array.prototype和Object.prototype挂上你自定义的属性和方法,不然,你以后可能要去找bug了。

以上所述就是本文的全部内容了,希望大家能够喜欢。

Javascript 相关文章推荐
Extjs中常用表单介绍与应用
Jun 07 Javascript
Jquery css函数用法(判断标签是否拥有某属性)
May 28 Javascript
原生js写的放大镜效果
Aug 22 Javascript
Jquery中扩展方法extend使用技巧
Aug 24 Javascript
浅谈javascript获取元素transform参数
Jul 24 Javascript
jQuery 1.9.1源码分析系列(十三)之位置大小操作
Dec 02 Javascript
AngularJS中的按需加载ocLazyLoad示例
Jan 11 Javascript
微信小程序 下拉菜单的实现
Apr 06 Javascript
js绑定事件和解绑事件
Apr 27 Javascript
在 Vue.js中优雅地使用全局事件的方法
Feb 01 Javascript
js实现固定区域内的不重叠随机圆
Oct 24 Javascript
使用Vant完成Dialog弹框案例
Nov 11 Javascript
纯js实现无限空间大小的本地存储
Jun 18 #Javascript
JS实现当前页居中分页效果的方法
Jun 18 #Javascript
javascript中Date()函数在各浏览器中的显示效果
Jun 18 #Javascript
javaScript中Math()函数注意事项
Jun 18 #Javascript
理解Javascript的动态语言特性
Jun 17 #Javascript
你所不了解的javascript操作DOM的细节知识点(一)
Jun 17 #Javascript
jQuery实现复选框批量选择与反选的方法
Jun 17 #Javascript
You might like
人族 Terran 基本策略
2020/03/14 星际争霸
特详细的PHPMYADMIN简明安装教程
2008/08/01 PHP
PHP MVC框架路由学习笔记
2016/03/02 PHP
php实现图片以base64显示的方法
2016/10/13 PHP
PHP编程求最大公约数与最小公倍数的方法示例
2017/05/29 PHP
PHP实现执行外部程序的方法详解
2017/08/17 PHP
Laravel实现短信注册的示例代码
2018/05/29 PHP
JavaScript 监听textarea中按键事件
2009/10/08 Javascript
使用jQuery避免鼠标双击的解决方案
2013/08/21 Javascript
js使用正则实现ReplaceAll全部替换的方法
2014/07/18 Javascript
最简单的JavaScript验证整数、小数、实数、有效位小数正则表达式
2015/04/17 Javascript
jQuery表格的维护和删除操作
2017/02/03 Javascript
jQuery插件echarts实现的多柱子柱状图效果示例【附demo源码下载】
2017/03/04 Javascript
微信小程序 侧滑删除(左滑删除)
2017/05/23 Javascript
微信小程序实现图片上传、删除和预览功能的方法
2017/12/18 Javascript
Python写的贪吃蛇游戏例子
2014/06/16 Python
Python实现简单多线程任务队列
2016/02/27 Python
Python 包含汉字的文件读写之每行末尾加上特定字符
2016/12/12 Python
python3实现小球转动抽奖小游戏
2020/04/15 Python
三步实现Django Paginator分页的方法
2019/06/11 Python
python 随机生成10位数密码的实现代码
2019/06/27 Python
Django和Flask框架优缺点对比
2019/10/24 Python
解析PyCharm Python运行权限问题
2020/01/08 Python
python数据类型强制转换实例详解
2020/06/22 Python
超30万乐谱下载:Musicnotes.com
2016/09/24 全球购物
女大学生自我鉴定
2013/12/09 职场文书
高分子材料与工程专业个人求职信
2013/12/15 职场文书
保险专业自荐信范文
2014/02/20 职场文书
乡村卫生服务一体化管理实施方案
2014/03/30 职场文书
信息管理与信息系统专业求职信
2014/06/21 职场文书
2015年个人实习工作总结
2014/12/12 职场文书
收银员岗位职责
2015/02/03 职场文书
如何使用flask将模型部署为服务
2021/05/13 Python
Mysql关于数据库是否应该使用外键约束详解说明
2021/10/24 MySQL
Python帮你解决手机qq微信内存占用太多问题
2022/02/15 Python
Python学习之包与模块详解
2022/03/19 Python