JavaScript(一)

基于《JavaScript高级程序设计》

基础语法与c类似,面向对象跟Java类似(我瞎说的

组成:

  • 核心(ECMAScript)
  • 文档对象模型(DOM)
  • 浏览器对象模型(BOM)

基本语法

  1. typeof(操作符) 检测给定变量的数据类型

    eg:

    1
    2
    typeof xxx
    typeof(xxx) // 两种格式都可
  2. var声明变量而未加以初始化时,变量的值为 undefined

  3. null 空对象指针 undefined 派生于其中,

    1
    null == undefined // 结果为true
  4. Boolean类型, 通过Boolean()函数可将一些数据类型转化。

    1
    Boolean(NaN) == false
  5. Object类型:是所有实例的基础

    1
    2
    var o = new Object() 
    var o = new Object // 不传参的情况下可省
  6. 无符号右移 >>>

  • 相等不相等:先转换操作数再比较
    1
    "55"==55 // true
  • 全等不全等 === / !== :直接比较
  1. 奇怪的操作:

    1
    var num=(5,6,7,8) //不报错,num被赋值为8
  2. for-in :枚举对象的属性

    1
    2
    3
    4
    for(var p in window){
    // 每一次循环都会将window的一个属性值赋给p
    document.write(p);
    }
  3. label:标记 与continue和break连用

  4. with 将代码的作用域设置到一个特定的对象中,个人感觉跟kotlin的apply语法糖类似
    eg:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var qs = location.search.substring(1);
    var hostName = location.hostname;
    var url = location.href;

    // 可写为
    with(location){
    var qs = search.substring(1);
    var hostName = hostname;
    var url = href;
    }

  5. function关键字声明函数

    eg:

    1
    2
    3
    function FunctionName(arg0, arg1, ... argN){
    statement here;
    }

    比较有趣的是命名的参数不是必需的,而是用来提供便利的,ECS5中函数的参数是一个 arguments对象,它与数组类似但不是数组的实例,可以通过arguments[0], arguments[1]... 来调用命名参数, arguments.length获取参数的个数即’数组’长度(由命名参数的个数决定)。在非严格模式下,修改命名参数的值会修改arguments对应的值,但注意它们的内存空间实际是相互独立的。 (我一开始还想的是命名参数会不会是arguments对应元素的指针。

  6. 没有重载


变量、作用域、内存问题

  • 基本类型值
    • 复制:直接产生副本
  • 引用类型值
    • 复制:产生的是指针的副本,即新的值是对旧对象的引用
  • 按值传递
    • 注意函数传值为对象类型时,产生了复制,从而可以修改外部对象的属性值

  1. 检测引用类型值 instanceof

    语法:

    1
    2
    // 变量是指定类型吗? 返回结果
    res = variable instanceof constructor ;
  2. 执行环境:都包含一个与之关联的变量对象。在一个环境中执行时,会创建变量对象的一个作用域链。其前端是所在环境定义的变量对象,然后逐级浮出,末端为全局变量。

  3. 延长作用域链

    • with 语句
    • try-catch块 :块外部也可访问内部错误对象
  4. 没有块作用域

    即if/for等声明的变量外部也可访问

  5. 垃圾清除

    由执行环境负责管理代码执行过程中使用的内存。

    • 标记清除(周期性执行):

      i. 标记进入环境的变量

      ii. 去除环境中的变量以及被环境中变量引用的变量(嵌套)的标记

      iii. 还有标记的变量被视为可删除的变量

      记得golang用的是三色标记法。

    • 引用计数

      基于引用次数,用的很少,存在“循环引用”的问题。

    • 有时候可能得手动解除引用


引用类型

  • 对象是某个特定引用类型的实例

  • 不同于类


  1. 创建对象

    • new Object()

    • 对象字面量

      1
      2
      3
      4
      5
      6
      var person = {
      name : "xxxx",
      age : xx
      };

      var person = {}; //等价于new Object()
  2. Array类型:每一项可以保存任意类型的数据,大小动态调整

    1
    2
    3
    4
    5
    6
    var array = new Array();
    var array = new Array(10); // 可以指定length
    var array = new Array("red", "yellow"); //可直接初始化
    var array = Array{}; // 可省略 new
    var array = []; // 数组字面量表示
    var array = ["red", "yellow"];
    • 通过索引进行访问

    • 索引超过数组现有项数,则数组长度会增长,新项添加到数组末尾

    • array.length 返回长度 可以通过该属性来对数组末尾添加值

      eg:

      1
      array[array.length] = "new_Items";
    • 检测方法:Array.isArray(array)

    • 继承了 toString()/toLocaleString()/valueOf() 方法

    • array.join("指定分隔符")

    • 栈/队列方法:

      eg:

      1
      2
      3
      4
      5
      6
      7
      var count = array.push(item1, item2); // 返回操作完成后数组的长度
      var item = array.pop();

      item = array.shift(); // 弹出队首项

      item = array.unshift(new_item); // 队首添加新项,与pop结合实现逆向队列操作

    • 排序方法:

      eg:

      1
      2
      array.reverse(); //逆向排
      array.sort(compare); // 默认升序,可接收一个自定义比较函数
    • 操作方法:

      eg:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      // concat()
      var colors = ["red", "blue", "green"];
      var colors2 = colors.concat("yellow", ["black", "brown"]);

      // slice() 通过索引创建
      var colors3 = colors.slice(0, 2) // 左闭右开

      // splice()

      // 删除指定项
      splice(0, 2) // 第一个参数为指定位置,第二个是需要删除的项数
      // 插入
      splice(1, 0, item1, item2, ...) //指定删除项数为0
      // 替换
      splice(1, 1, new_item) // 添加数与删除数不需要相等
    • 位置方法:

      indexOf() / lastIndexOf() 都接受两个参数,第一个是查找的项,第二个是查找的起始位置,返回值为在数组的索引。

    • 迭代方法:对每一项执行给定函数

      every() filter() forEach() map() some()

    • 归并方法:reduce() reduceRight() 后者只不过是反过来而已,接收的参数为一个函数,其有四个参数,前一个值,当前值,项的索引,数组对象。

      eg: 累加求数组和

      1
      2
      3
      4
      var values = [1,2,3,4,5]
      var sum = values.reduce(function(prev, cur, index, array){
      return prev + cur
      }); //15
  3. Date()类型,用的时候查

  4. RegExp类型 : 支持正则表达式

    基本格式:var exp = / pattern / flags

    • pattern : 正则表达式

    • flags : 每个正则表达式可带的一个或多个表达式

      • g 全局模式
      • i 不区分大小写
      • m 多行模式

      eg:

      1
      2
      3
      4
      5
      6
          
      //1. 正则表达式字面量
      var pattern1 = /[bc]at/i;

      //2. RegExp构造函数
      var pattern2 = new RegExp("[bc]at", "i") // 个人觉得这个可读性强些
    • 方法:

      i. exec() 接收一个参数为待匹配的字符串,返回包含一个Array的实例或者null该实例包含indexinput两个额外属性,前者表示匹配项的索引,后者表示应用的正则表达式字符串。数组的第一项相当于模式匹配的第一部分,后续项数由捕获组确定。

      ii. test() 接收一个参数,返回输入文本与模式是否匹配

  1. Function类型:每个函数都是Function类型的实例

    • 函数名仅仅是指向函数的指针

    • 函数表达式实例:

      eg:

      1
      2
      3
      var sum = function(num1, num2){
      return num1 + num2;
      };
    • 解析器会率先解析函数声明,javaScript引擎会声明函数并将其放到源代码树的顶部,所以以下例子是正确的:
      eg:

      1
      2
      3
      4
      alert(sum(10,10)); // 20
      function sum(num1, num2){
      return num1 + num2;
      }

      但是函数表达式不行,你可以理解为使用了未声明的变量

    • 去掉函数名后面的那对圆括号,意味着访问函数的指针但不执行函数

    • 函数内部属性:

      • arguments 之前介绍过大部分。其有一个属性callee为指针类型指向拥有这个arguments对象的函数

      • this 引用函数执行的环境对象

      • caller 调用当前函数的函数的引用(即存在嵌套调用)

      • length 函数希望接收的参数的个数

      • apply 第一个参数是运行函数的作用域即this表当前函数运行环境(全局的话就是window对象),第二个为参数数组

        call 第一个参数为this,后面的为所有需要传递的参数

        两者可用于扩充作用域

        bind(对象名) 创建函数实例,并绑定传给bind()函数的值给this

  1. 基本包装类型:Boolean, Number, String

    • 不建议显示地创建基本包装类型

    • 自动创建的基本包装类型,只存在于一行代码的执行瞬间,因此不能为其显示的再创建属性(因为会立马被销毁)

    • 永远不使用Boolean对象(没啥用感觉)

    • Number:

      • tofixed(n) : 按照指定小数位数返回数值的字符串

      • toExponential() : 指数形式(e型)

      • toPrecision(n) :按照指定位数显示

      • 不建议用

    • String:

      • charAt(n) : 返回给定位置的单个字符 charCodeAt(n) 得到字符的ASCII编码

      • concat()

      • slice() / substring() / substr()

      • indexOf() / lastIndexOf()

      • trim() 创建字符串副本,并删除前后所有空格

      • 大小写转换的一些函数

      • 模式匹配 match(pattern) 与RegExp的exec()类似 search(pattern) 返回查找到的位置

        replace(pattern, new_str) 替换 第二个参数也可以是函数

      • split(xx) 基于指定的分隔符将一个字符串分割成多个子字符串,并放在一个数组中返回,第二个参数可选,指定数组的大小

      • 其它 localeCompare(xxx) 字母表排序

        fromCharCode(xxx,xxx,...) 接收多个字符编码转换为字符串

  2. 单体内置对象:由ECS实现提供,不依赖于宿主环境

    • Global : ‘兜底儿对象’

      • eval(xxx) 相当于解析器,可以接受任意js语句
    • Math :

      对数组进行排序,可以调用

      1
      Math.min.apply(Math, array)

      正确指定this指针的值