JavaScript学习笔记

Posted 君兮月影

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript学习笔记相关的知识,希望对你有一定的参考价值。

文章目录

第1章:什么是javascript

1. JavaScript实现

  1. 核心(ECMAScript):由ECMA-262定义并提供核心功能
  2. 文档对象模型(DOM):提供与网页内容交互的方法和接口
  3. 浏览器对象模型(BOM):提供与浏览器交互的方法和接口

2. ECMAScript

  1. ECMA-262定义的一种语言基准,在此基础上构建更稳健的脚本语言
  2. Web浏览器只是ECMAScript实现的一种宿主环境(host environment),Node.js是服务器端JavaScript平台,也是一种宿主环境。
  3. ECMA-262定义了:语法,类型,语句,关键字,保留字,操作符,全局对象

3. DOM

  1. 文档对象模型,Document Object Model,是API。
  2. DOM将页面抽象为一组分层节点,创建表示文档的树。

4. BOM

  1. 浏览器对象模型,也是API。
  2. 通常把任何特定于浏览器的扩展都归在BOM的范畴内。
  3. 没有标准,html5之后,BOM实现细节日趋一致。

第2章:HTML中的JavaScript

1.<Script>元素

  1. 将JavaScript插入HTML的主要方法是使用<script>元素
  2. 是HTML规范
  3. <script>元素有8个属性
    • async:可选。立即开始下载脚本,但不阻止其他页面动作,异步。
    • charset:可选。使用src属性指定的代码字符集,很少用,因为大多数浏览器不care它的值。
    • crossorigin:可选。配置相关请求的CORS(跨资源共享)设置,默认不使用CORS。
    • defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。
    • integrity:可选。用于确保内容分发网络(CDN,Content Delivery Network)不会提供恶意内容。
    • language:废弃。
    • src:可选。表示包含要执行的代码的外部文件的URL,可以跟网页在同一台服务器上,也可以位于完全不同的域。
    • type:可选。代替language,表示代码块中脚本语言的内容类型(也称MIME类型)。例:“text/javascript”
  4. 使用方式
    • 网页中嵌入JavaScript代码
    • 在网页中包含JavaScript文件
  5. 使用了src属性的<script>元素不应该再在<script>和</script>标签中再包含其他JavaScript代码。如果两者都提供的话,浏览器只会下载并执行脚本文件,忽略行内代码。
  6. 建议将JavaScript引用放在<body>元素中的页面内容后面,因为页面在浏览器解析到<body>的起始标签时开始渲染,放在前面会导致页面渲染的明显延迟。
  7. 推迟执行脚本:defer属性。该属性只对外部脚本文件有效。HTML5规范要求脚本应该按照出现顺序执行,所以第一个defer的脚本会在第二个defer的脚本之前执行。但实际上不一定,so最好只包含一个defer脚本。因为有的浏览器会忽略这个属性,所以还是把要推迟执行的脚本放在页面底部比较好。
  8. 异步执行脚本:async属性。也只适用于外部脚本。但是标记为async的脚本不能保证按照出现次序执行,因为它们之间没有依赖关系。
  9. 动态加在脚本:使用DOM API,通过向DOM中动态添加script元素加载指定的脚本。只要创建一个script元素并将其添加到DOM即可。这种方式以异步加载,相当于添加了async属性,但是不是所有的浏览器都支持这个属性,所以可以将其设置为同步加载。
    let script =document.createElemnet('script')`` script.src='gibberish.js' script.async = false; // 设置为同步加载 document.head.apendChild(script)
    这种方式获取的资源对浏览器的预加载器不可见,严重影响性能。要想让预加载器知道动态请求文件的存在,可以在文档头部显式声明它们:
    <link rel="preload" href="gibberish.js">
  10. XHTML中的变化:XHTML中使用JavaScript必须指定type属性且值为text/javascript。XHTML模式会在页面的MIME类型被指定为"application/xhtml+xml"时触发。

2.行内代码于外部文件

  1. 推荐使用外部文件,理由如下
    • 可维护性。用一个目录保存所有的js文件,更容易维护,开发者可以独立于使用它们的HTML页面来编辑代码。
    • 缓存。浏览器会根据特定的设置缓存所有外部链接的js文件,所以如果两个页面都用到同一个文件,只需要下载一次,从而使页面加载更快。
    • 适应未来。包含外部js文件的语法在HTML和XHTML中一样。

3.文档模式

  1. 使用doctype切换文档模式
    • 混杂模式(quirks mode):省略文档开头的doctype声明
    • 标准模式(standards mode)
    • 准标准模式(almost standards mode)

4.<noscript>元素

  1. 用于给不支持js的浏览器提供替代内容。
  2. 如今的浏览器已经100%支持js
  3. 对于禁用js的浏览器来说,这个元素有用

第3章 语言基础

1.语法

  1. 区分大小写
  2. 标识符:
    • 可以由一个或多个字符组成,第一个字符必须是一个字母,下划线(_)或美元符号($),剩下的其他字符可以是字母、下划线、美元符号或数字。
    • 按照惯例使用驼峰大小写形式,不是强制性的。
    • 关键字、保留字、true、false和null不能作为标识符。
  3. 注释:
    • 单行注释:// 注释内容
    • 多行注释:/* 注释内容 */
  4. 严格模式(strict mode):
    • "use strict"启用严格模式,可以对整个脚本启用,也可以对指定函数启用,这是一个预处理指令。
    • 所有现代浏览器都支持严格模式。
  5. 语句
    • 以分号结尾,没有分号意味着由解析器确定语句在哪结尾,也有效,但不推荐。
    • 多条语句可以合并到一个代码块中,代码块由 ‘’ 标识开始,''标识结束。
    • if之类的控制语句只在执行多条语句时要求必须有代码块,但推荐加代码块,减少出错。

2.关键字与保留字

  1. 关键字
  2. 保留字

3.变量

  1. var关键字
    • 可以保存任何类型的值,没有初始化的情况下保存一个特殊值undefined
    • 可以同时定义变量并设置它的值
    • 可以改变保存的值,也可以改变值的类型
    • var声明作用域:在函数内部定义的变量只在函数内部有效,在函数内定义变量时省略var操作符,可以创建一个全局变量,但不推荐这么做。
    • 定义多个变量可以在一条语句中用逗号分隔
    • var声明提升:var声明的变量会自动提升到函数作用域顶部
    • 反复使用var声明同一个变量也没有问题
  2. let声明
    • let声明的范围是块作用域,而var声明的范围是函数作用域,块作用域是函数作用域的子集
    • let不允许同一个块作用域中出现冗余声明
    • 暂时性死区:let与var的一个重要区别是,let声明的变量不会在作用域中被提升。let声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出ReferenceError。
    • 全局声明:let在全局作用域中声明的变量不会成为window对象的属性(var声明的变量会)。
    • 条件声明:不能使用let进行条件式声明(条件声明是一种反模式)
    • for循环中的let声明:使用let声明for循环中的迭代变量,则变量的作用域仅限于for循环块内部,不会出现渗透到循环体外部的情况。
  3. const声明
    • 声明变量时必须同时初始化变量。
    • 尝试修改const声明的变量会导致运行时错误。不能声明迭代变量。
    • 不允许重复声明。
    • 声明的作用域也是块。
    • const声明的限制只适用于它指向的变量的引用,可以修改这个对象内部的属性。
  4. 声明风格及最佳实践
    • 不使用var
    • const优先,let次之

4.数据类型

  1. 简单数据类型:Undefined、Null、Boolean、Number、String和Symbol。
  2. 复杂数据类型:Object
  3. typeof操作符:用来确定变量的数据类型,只是一个操作符,不是函数,不需要参数(当然也可以使用参数)
  4. Undefined类型:
    • 只有一个值,就是特殊值undefined。
    • 当var和let声明了变量但是没有初始化时,默认给变量赋值undefined。
    • 不必显式地将变量值设置为undefined。
  5. 注意:无论是声明后未赋值还是未声明,typeof返回的都是"undefined",逻辑上是对的。建议在声明变量的同时初始化,这样当typeof返回"undefined"的时候就知道是未声明而不是声明了但未初始化。
  6. Null类型:
    • 只有一个值,特殊值null。表示一个空对象指针。
    • 当一个变量要保存对象而又没有对象可保存时,将变量显式的赋值为null。
  7. 注意:用比较操作符(==)比较null和undefined始终返回true。
  8. Boolean类型:
    • 有两个字面值:true,false
    • Boolean()转型函数:将其他类型的值转换为布尔值
  9. Number类型
    • 八进制:第一位必须为0,严格模式下无效。应该使用前缀0o
    • 十六进制:前缀0x。
    • 浮点值:
      • 数值中必须包含小数点,小数点后面必须至少有一个数字。小数点前不是必须有整数,但推荐加上。
      • 科学计数法表示:一个数值(整数或浮点数)后跟一个大写或小写的字母e,再加上一个要乘的10的多少次幂。例:3.125e7,3e-17。
    • 值的范围:
      • 最小值:Number.MIN_VALUE,大概是5e-324。
      • 最大值:Number.MAX_VALUE,大概是1.797 693 134 862 315 7e+308。
      • 任何无法表示的负数:-Infinity(负无穷大),Number.NEGATIVE_INFINITY
      • 任何无法表示的正数:Infinity(正无穷大),Number.POSITIVE_INFINITY
      • 如果计算返回正 Infinity 或负 Infinity,则该值将不能再进一步用于任何计算。
      • isFinite()函数:用于确定一个数是不是有限大。
    • NaN
      • 不是数值,not a number。用于表示本来要返回数值的操作失败了。
      • 任何涉及NaN的操作始终返回NaN。
      • NaN不等于包括NaN在内的任何值。
      • isNaN()函数:接受一个参数,判断该参数是否“不是数值”。
    • 数值转换:有三个函数可以将非数值转换为数值
      • Number():可用于任何数据类型。
      • parseInt():主要用于将字符串转换为数值。可以接收两个参数,第二个参数表示底数(进制数)。建议给第二个参数。
      • parseFloat():主要用于将字符串转换为数值。
  10. String类型
    • 0个或多个16位Unicode字符序列
    • 可以用双引号(")、单引号(')或反引号(`)标示
    • 字符串的长度通过length属性过去,例:text.length
    • toString()方法:把一个值转换为字符串。对数值调用这个方法时,可以接受一个底数参数。null和undefined值没有这个方法。
    • String():当不确定一个值是不是null或undefined时用。
    • 用加号操作符给一个值加上一个空字符串""也可以将其转换为字符串。
    • 字符串差值:通过在$中使用一个JavaScript表达式实现。嵌套的模板字符串无须转义,在插值表达式中可以调用函数和方法。模板也可以插入自己之前的值。
    • 模板字面量标签函数(没看懂!,到底什么是标签函数啊?)第67页
    • 原始字符串:String.raw标签函数,也可以通过标签函数的raw属性获得每个字符串的原始内容
  11. Symbol类型:(这里面蛮多不懂的地方,用到的时候再回来看)
    • 符号类型,确保对象属性使用唯一标识符。
    • 基本用法:
      • 使用Symbol()函数初始化。let sym = Symbol();
      • 调用Symbol()函数时,可以传入一个字符串参数作为对符号的描述,let othersym = Symbol(‘foo’);这个字符串参数可以用来调试代码,但是与符号定义或标识完全无关。
      • 符号没有字面量语法
      • Symbol()函数不能与new关键字一起作为构造函数使用
        let mySymbol = new Symbol(); // TypeError: Symbol is not a constructor
    • 使用全局符号注册表
      • 使用Symbol.for()方法:let fooGlobalSymbol = Symbol.for('foo');
      • 在全局注册表中定义的符号跟使用Symbol()定义的符号并不等同。
      • 全局注册表中的符号必须使用字符串来创建,因此作为参数传给Symbol.for()的任何值都会被转换为字符串。注册表中使用的键同时也会被用作符号描述。
        let emptyGlobalSymbol = Symbol.for();
        console.log(emptyGlobalSymbol); // Symbol(undefined)
      • 使用Symbol.keyFor()来查询全局注册表,返回该全局符号对应的字符串键。
        // 创建全局符号
        let s = Symbol.for('foo');
        console.log(Symbol.keyFor(s)); // foo
    • 使用符号作为属性(从这里开始往下的符号部分的内容没看懂,用到的时候再回来看)
    • 常用内置符号
  12. Object类型:
    • 对象实际就是一组数据和功能的集合。通过new操作符后跟对象类型的名称来创建(同Java)。例:let o = new Object();
    • 如果构造函数没有参数,可以省略括号,合法但不推荐。
    • 每个Object实例都有以下属性和方法:
      • constructor:用于创建当前对象的函数。
      • hasOwnProperty(propertyName):用于判断当前对象实例上是否存在给定的属性。
      • isPrototypeOf(Object):用于判断当前对象是否为另一个对象的原型。
      • propertyIsEnumerable(propertyName):用于判断给定的属性是否可以使用for-in语句枚举。
      • toLocaleString():返回对象的字符串表示,该字符串反映对象所在的本地化执行环境。
      • toString():返回对象的字符串表示。
      • valueOf():返回对象对应的字符串、数值或布尔值表示。
    • Object是所有对象的基类,所以任何对象都有这些属性和方法。

5.操作符

  1. 一元操作符
    • 递增/递减操作符
      • 同C语言
      • 可以作用于任何值,整数,字符串,布尔值,浮点值甚至对象都可以。
    • 一元加和减
      • 同高中数学
      • 应用到非数值时会执行于使用Number()转型函数一样的类型转换。
      • 一元加(+)放到变量前头,对数值没有任何影响。
      • 一元减(-)放在变量前头,主要用于把数值变成负值。
      • 主要用于基本算数,也可用于数据类型转换。
  2. 位操作符
    • 在应用位操作时,在后台64位数值会转换为32位数值,然后执行位操作,最后再把结果从32位转换为64位存储起来。副作用是:特殊值NaN和Infinity在位操作中都会被当成0处理。
    • 应用到非数值,首先会使用Number()函数将该值转换为数值。
    • 按位非(~):返回数值的补数。
    • 按位与(&)
    • 按位或(|)
    • 按位异或(^)
    • 左移(<<):保留符号。
    • 有符号右移(>>):保留符号
    • 无符号右移(>>>)
  3. 布尔操作符
    • 逻辑非(!)
      • 返回值一定是布尔值。
      • 首先将操作符转换为布尔值,然后对其取反。
      • 同时使用两个叹号(!!),相当于调用了转型函数Boolean()。
      • 规则:
        如果操作数是对象,则返回false。
        如果操作数是空字符串,则返回true。
        如果操作数是非空字符串,则返回false。
        如果操作数是数值0,则返回true。
        如果操作数是非0 数值(包括Infinity),则返回false。
        如果操作数是null,则返回true。
        如果操作数是NaN,则返回true。
        如果操作数是undefined,则返回true。
    • 逻辑与(&&)
      • 如果有操作数不是布尔值,返回值不一定是布尔值。
      • 规则:
        如果第一个操作数是对象,则返回第二个操作数。
        如果第二个操作数是对象,则只有第一个操作数求值为true才会返回该对象。
        如果两个操作数都是对象,则返回第二个操作数。
        如果有一个操作数是null,则返回null。
        如果有一个操作数是NaN,则返回NaN。
        如果有一个操作数是undefined,则返回NaN。
    • 逻辑或(||)
      • 如果有操作数不是布尔值,返回值不一定是布尔值。
      • 规则
        如果第一个操作数是对象,则返回第一个操作数。
        如果第一个操作数求值为false,则返回第二个操作数。
        如果两个操作数都是对象,则返回第一个操作数。
        如果两个操作数都是null,则返回null。
        如果两个操作数都是NaN,则返回NaN。
        如果两个操作数都是undefined,则返回undefined。
  4. 乘性操作符:乘法、除法和取模。作用同Java,C语言。当操作数不是数值时,会在后台使用Number()转型函数转换为数值。
    • 乘法(*)
      • 操作符都是数值,执行常规乘法运算。如果不能表示乘积,则返回Infinity或-Infinity。
      • 如果有任一操作数是NaN,则返回NaN。
      • 如果是Infinity乘以0,则返回NaN。
      • 如果是Infinity乘以非0的有限数值,则根据第二个操作数的符号返回Infinity或-Infinity。
      • 如果是Infinity乘以Infinity,则返回Infinity。
      • 如果不是数值的操作数,则先在后台用Number()将其转换为数值,然后再应用上述规则。
    • 除法(/)
      • 操作符都是数值,执行常规除法运算。如果不能表示商,则返回Infinity或-Infinity。
      • 如果有任一操作数是NaN,则返回NaN。
      • 如果是Infinity除以Infinity,则返回NaN。
      • 如果是0除以0,则返回NaN。
      • 如果是非0的有限值除以0,则根据第一个操作数的符号返回Infinity或-Infinity。
      • 如果是Infinity除以任何值,则根据第二个操作数的符号返回Infinity或-Infinity。
      • 如果不是数值的操作数,则先在后台用Number()将其转换为数值,然后再应用上述规则。
    • 取模(%)
      • 如果操作数是数值,则执行常规除法运算,返回余数。
      • 如果被除数是无限值,除数是有限值,则返回NaN。
      • 如果被除数是有限值,除数是0,则返回NaN。
      • 如果是Infinity除以Infinity,则返回NaN。
      • 如果被除数是有限值,除数是无限值,则返回被除数。
      • 如果被除数是0,除数不是0,则返回0。
      • 如果不是数值的操作数,则先在后台用Number()将其转换为数值,然后再应用上述规则。
  5. 指数操作符:**
    • 等价于Math.pow()
    • 指数操作符也有自己的指数赋值操作符**=
  6. 加性操作符
    • 加法操作符(+)
    • 减法操作符(-)
  7. 关系操作符:都返回布尔值
    • 小于(<)
    • 大于(>)
    • 小于等于(<=)
    • 大于等于(>=)
  8. 相等操作符
    • 等于(==)和不等于(!=):先进行类型转换,再确定操作数是否相等。
    • 全等(===)和不全等(!==):比较相等时不转换操作数。
  9. 条件操作符:同Java中的三目运算符
    • variable = boolean_expression ? true_value : false_value;
  10. 赋值操作符
    • 简单赋值(=)
    • 复合赋值:使用乘性、加性或位操作符后跟等于号(=)表示
  11. 逗号操作符(,):可以用来在一条语句中执行多个操作

6.语句

  1. if语句:
    • if(condition) statement1 else statement2;
    • if(condition1) statement1 else if(condition2) statement2 else statement3;
  2. do-while语句
  3. while语句
  4. for语句:建议使用let声明迭代器变量
  5. for-in语句
    • 建议使用const声明变量
    • for(const property in expression) statement;
    • ECMAScript中对象的属性是无序的。因此for-in语句不能保证返回对象属性的顺序。
  6. for-of语句
    • 一种严格的迭代语句,用于遍历可迭代对象的元素
    • for(property of expression) statement;
    • 建议使用const声明迭代变量
    • 会按照可迭代对象的next()方法产生值的顺序迭代元素
  7. 标签语句
    • 用于给语句加标签,语法:label: statement
    • 标签可以通过break或continue语句引用。(不太明白)
  8. break和continue语句
    • break:立即退出循环,强制执行循环后的下一条语句。
    • continue:立即退出循环,再次从循环顶部开始执行。
    • 可以与标签语句一起使用,返回代码中特定的位置。(明白了)
  9. with语句
    • 用途是将作用域设置为特定的对象,语法:with(expression) statement;
    • 主要场景是针对一个对象反复操作
    • 严格模式不允许使用with语句,会抛出错误。
    • 影响性能难调试,不推荐使用!
  10. switch语句(同Java)

7.函数

  1. 使用function关键字声明,后跟一组参数,然后是函数体。
    function functionName(arg0,arg1,…,argN)
    statements
  2. 使用函数名调用函数
  3. 不需要指定是否返回值,任何函数在任何时间都可以使用return语句来返回函数的值
  4. 不指定返回值的函数实际上会返回特殊值undefined

Java程序猿的JavaScript学习笔记(9—— jQuery工具方法)

计划按例如以下顺序完毕这篇笔记:
 

  1. Java程序猿的JavaScript学习笔记(1——理念)
  2. Java程序猿的JavaScript学习笔记(2——属性复制和继承)
  3. Java程序猿的JavaScript学习笔记(3——this/call/apply)
  4. Java程序猿的JavaScript学习笔记(4——this/闭包/getter/setter)
  5. Java程序猿的JavaScript学习笔记(5——prototype)
  6. Java程序猿的JavaScript学习笔记(6——面向对象模拟)
  7. Java程序猿的JavaScript学习笔记(7——jQuery基本机制)
  8. Java程序猿的JavaScript学习笔记(8——jQuery选择器)
  9. Java程序猿的JavaScript学习笔记(9——jQuery工具方法)
  10. Java程序猿的JavaScript学习笔记(10——jQuery-在“类”层面扩展)
  11. Java程序猿的JavaScript学习笔记(11——jQuery-在“对象”层面扩展)
  12. Java程序猿的JavaScript学习笔记(12——jQuery-扩展选择器)
  13. Java程序猿的JavaScript学习笔记(13——jQuery UI)
  14. Java程序猿的JavaScript学习笔记(14——扩展jQuery UI)

这是笔记的第9篇,从jQuery源代码的角度。聊聊jQuery的工具方法。


作者博客:http://blog.csdn.net/stationxp

作者微博:http://weibo.com/liuhailong2008

转载请取得作者允许


1、先看几个工具方法怎样使用:

var t = $.trim('   >>_<<   ');
var ps = $.param({x:15,y:16});
jQuery.type(function(){}) === "function"

jQuery的工具方法,相对jQuery本身,是相对独立的。

2、这些方法是怎样定义的呢?
我们推測一下,试试看。


我们知道jQuery(即$)是全局变量。这些方法应该是jQuery变量的属性。


我们能够通过例如以下语法加入:

jQuery.xx = function(a,b){
	 return a + b;
}
// try
var r1 = jQuery.xx(2,3);
console.log(r1);// output : 5
var r2 = $.xx(3,3);
console.log(r2);// output : 6
上面代码。说明$和jQuery引用了同样变量,他们是一样一样的。


这些代码达到了定义工具方法的目的,但jQuery是这样做的吗?

3、
查看jQuery源码。jQuery通过例如以下语法定义工具方法:

jQuery.extend({
	 noConflict: function( deep ) {
	  if ( window.$ === jQuery ) {
			window.$ = _$;
	  }
	  if ( deep && window.jQuery === jQuery ) {
			window.jQuery = _jQuery;
	  }
	  return jQuery;
	 }
	 //, ...
 });

extend方法定义例如以下:

//定义了一个方法,赋值给jQuery.fn.extend和jQuery.extend.
//jQuery.fn.extend和jQuery.extend尽管定义同样,但调用者不同,从而方法中this指向不同。从而实现的功能不同。
//没有显式声明參数,而是通过arguments动态获得,从而支持更丰富的功能。

jQuery.extend = jQuery.fn.extend = function() { var src, copyIsArray, copy, name, options, clone, // 将第一个參数作为目标对象 target = arguments[0] || {}, // i初始化为1,临时还不知道做什么用 i = 1, // length表示參数的个数 length = arguments.length, // deep 应该表示是否深层拷贝,默觉得否。 deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { //假设第一个參数是布尔类型,则第二个參数为目标对象 //形如:jQuery.extend(false,UiObject,...); deep = target; target = arguments[1] || {}; // i 是当前參数的数组下标,从0開始 i = 2; } //目标对象是能是函数或者对象,传入其它參数,target默觉得空对象。

if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // 眼下,假设第一个參数不是布尔。i值为1。length也为1,即extend(obj)的情况 // 假设是布尔,i值为2,length也为2,即extend(true,obj)的情况 // 总之。没有传入 src if ( length === i ) { // jQuery 把传入參数收了 // 參数下标又一次指向传入的这个參数,即此时指向了src target = this; --i; } // 如今i指向了target后面某个參数。应该是src // 把后面传入的每一个參数都当src for ( ;i < length; i++ ) { // Only deal with non-null/undefined values // 这样过滤非空啊,假设是undefined会被过滤掉吗? // 不做 typeof src 是否 "object"、"function"的推断吗? if ( (options = arguments[ i ]) != null ) { // 赋值给变量 options // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // 思虑万全:假设已经是自家人,就别嘚瑟了 // Prevent never-ending loop if ( target === copy ) { continue; } // 对普通对象和数组。考虑递归深层拷贝 // 问题来了,什么叫普通对象? function 算不算? 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 : {}; } //递归调 //假设写成 jQuery.extend( deep, clone, copy ) 是否一样 // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values // 对 undefined 和 != null 还要加深理解 } else if ( copy !== undefined ) { // 临门一脚。假设是 jQuery.extend({xx,xfasf});的情况。扩展的是this,即调用者。

// 对target直接改动。也没创建clone啥的 target[ name ] = copy; } } } } // Return the modified object return target; };

4、再看看jQuery.isPlainObject怎样定义的

 isPlainObject: function( obj ) {
  
	  // Must be an Object.
	  // Because of IE, we also have to check the presence of the constructor property.
	  // Make sure that DOM nodes and window objects don't pass through, as well
	  // 翻译:
	  // 必须是一个对象。

// 由于IE的缘故。我们还必须检查是否有constructor属性。

// 确认别放过Dom节点和window对象,他们不是普通对象。 if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { // 下面不通过空、undefined、0、jQuery.type返回不是object的、dom对象、window对象 // 所以 typeof 为string、number、function、正则、date的都不成 return false; } try { // Not own constructor property must be Object if ( obj.constructor && !core_hasOwn.call(obj, "constructor") && !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // 枚举的时候。自有属性会先被枚举出来。假设最后一个属性是自有属性。那么全部属性都是自有属性。 // 简而言之,不能有继承来的。能够被枚举到的属性,你妹。为什么有这种要求? // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for ( key in obj ) {} return key === undefined || core_hasOwn.call( obj, key ); }

5、
试试看

jQuery.extend({
 <span style="white-space:pre">	</span>sayHi:function(you){
  <span style="white-space:pre">		</span>console.log('hi',you);
 <span style="white-space:pre">	</span>}
});
$.sayHi('Stanley'); // output : hi Stanley

还不错!

假设想覆盖jQuery已有的方法呢?

jQuery.extend({
	 isPlainObject:function(obj){
			return 'baby, I am not sure.';
	 }
});
var r = $.isPlainObject({});
console.log(r); // output : baby, I am not sure.

这...好吧,能够得逞。想想别的办法吧,不能这样。

再玩儿:

jQuery.extend({
	 extend:function(obj){
		  // do nothing
		  return 'who am i?';
	 }
});
var r = $.extend({x:function(){ alert();}});
console.log(r); // output : who am i?
jQuery.x();// error : function not be defined

又得逞,这样。再没人能够通过extend扩展jQuery的方法了。
但能够有更直接的方法。



















以上是关于JavaScript学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

Java程序猿的JavaScript学习笔记(9—— jQuery工具方法)

Java程序猿的JavaScript学习笔记(12——jQuery-扩展选择器)

JavaScript学习笔记(12)——JavaScript内置对象

JavaScript学习笔记——JavaScript语法之对象

[JavaScript] 学习笔记-JavaScript基础教程

JavaScript学习笔记——JavaScript语法之函数