本博客采用创作共用版权协议, 要求署名、非商业用途和保持一致. 转载本博客文章必须也遵循署名-非商业用途-保持一致 的创作共用协议.
写作意图: 一直通过一些视频或者网页零碎的学习JavaScript, 整个语言一直难以形成系统, 所以希望利用一些时间系统的学习一下JavaScript语言.
写作目标:
希望构建JavaScript语言体系, 将零碎知识点系统化
希望以简单的语言, 能够使有编程基础的人快速入门JavaScript
注意: 本书并不针对零基础者, 很多基础内容会一笔带过, 本书大部分内容基于<JavaScript权威指南>进行总结.
#0. JavaScript概述
JavaScript是一门高端的, 动态的, 弱类型的编程语言
语言区分大小写
用unicode编码编写
注释使用// 单行注释或者/* 多行注释 */, 和C++相同
以;作为行间分隔符可选, 可以使用C++风格或者Python风格
#1. 类型/值和变量
JavaScript的数据类型分为: 原始类型和对象类型.
原始类型包括数字类型, 字符串类型, 布尔类型, null和undefined(最后两种是特殊的原始值)
对象类型包括普通对象, 具有特有行为的array数组对象和函数对象
JavaScript的数据类型也可分为: 可变类型和不可变类型
可变类型包括数组和对象(可变类型的比较是引用的比较)
不可变类型包括数字类型, 字符串类型, 布尔类型, null和undefined(不可变类型的比较为值的比较)
1 2 3 4 5 6 7 8 var a = [], b = [];a === b; var a = [];var b = a;b[0 ] = 1 ; a[0 ]; a === b;
JavaScript变量是无类型的, 可以被赋予任何类型值
数字
JavaScript无整数和浮点数之分, 所有数字都用浮点数(IEEE754)表示
JavaScript中算数运算在溢出, 下溢或被零整除时不会报错, 溢出或者被零整除返回Infinity或-Infinity, 下溢返回0和-0,
判断变量x是否是NaN(非数字值), 若x != x为true, 则x为NaN
字符串
1 2 3 4 "" 'string' "JavaScript" 'name = "Andrew"'
支持字符串+拼接操作
字符串length属性, str.length
支持定位, 取子串, 切片, 分割, 替换等字符串操作
字符串本身是不可变的!
布尔值
true和false
undefined, null, 0, -0, NaN, “”转换为false
其他值包括对象(数组)会转换成true
类型转换
显式类型转换
1 2 3 4 Number ("3" ); String (false ); Boolean ([]); Object (3 );
隐式类型转换
+运算一个操作数是字符串, 会将另一个操作数转换为字符串
!运算会把操作数转换为布尔值
变量声明
使用var关键字声明
1 2 3 var i = 0 ;var str = "hello" ;var first = function ( ) {}
作用域
函数体内, 同名局部变量的优先级高于全局变量(局部变量和全局变量同名不是好的编程习惯)
JavaScript中没有块级作用域, 使用函数作用域(函数内声明在整个函数体都是可见的)
#2. 表达式和运算符 1 2 3 4 5 6 7 8 var matrix = [1 , 2 , 3 ]; var p = { x : 2.3 , y : 1.8 }; var square = function { return x * x; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 基本算术表达式: + - * / % 一元算术运算符: + - ++ -- 位运算符: & | ~ << >> >>> 比较运算符: < > <= >= == === 逻辑表达式: && || ! 三目运算符: ? : typeof (typeof value == "string" ) ? "'" + value + "'" : value; delete var o = {x : 1 , y : 2 }delete o.x ;"x" in o; in var point = { x : 1 , y : 1 };"x" in point; "z" in point; instanceof var d = new Date ();d instanceof Date ; d instanceof Number ;
#3. 语句 定义变量
1 2 3 4 var x = 2 , f = function (x ) { return x * x; }, y = f (x);
定义函数
1 2 3 4 5 6 function funcname ([arg1 [, arg2 [..., argn]]] ) { statement; } var f = function (x ) { return x * x; }
if else语句
1 2 3 4 5 6 7 8 9 if (expression) { } else if (expression) { } else { }
switch语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 switch (expression) { case value1 : break ; case value2 : break ; case value3 : break ; default : break ; }
四种循环while,do-while,for,for-in
1 2 3 4 5 6 7 8 9 10 11 12 while (expression) { statement; } do { statement; } while (expression); for (initialize; test; increment) { statement; } for (variable in object) { statement; }
break语句跳转到循环(最内层)或者其他语句结束
continue语句终止本次循环并开始下一次循环
return语句让解释器跳出函数体执行(直接return; 返回的是undefined)
throw语句触发或者抛出一个异常
#4. 对象
JavaScript对象都是关联数组 所有JavaScript对象都从Object.prototype继承属性
创建对象
三种方法:
1 2 3 var point = {x : 0 , y : 1 }; var point1 = new Object (); var point2 = Object .create ({x : 1 , y : 2 });
查询和设置属性
1 2 var first = point.x ; var second = point["y" ];
删除属性
1 2 delete point.x ;(delete point["y" ]) == true ;
delete不可删除继承属性, 只能删除自有属性
检测属性
1 2 3 4 "x" in point; "toString" in point point.hasOwnProperty ("toString" ); point.propertyIsEnumerable ("toString" );
枚举属性
1 2 3 4 5 6 7 8 for (p in point) { if (!point.hasOwnProperty (p)) continue ; else if (typeof point[p] === "function" ) continue ; else : console .log (p); }
属性getter和setter
1 2 3 4 5 6 var point = { date_prop : value, get accessor_prop () {}, set accessor_prop (value ) {} };
对象的三属性
原型prototype
类class
可扩展性extensible attribute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 var p = {x : 1 };var o = Object .create (p);p.isPrototypeOf (o); Object .prototype .isPrototypeOf (p); function classof (o ) { if (o === null ) { return "Null" ; } if (o === undefined ) { return "Undefined" ; } return Object .prototype .toString .call (o).slice (8 , -1 ); }
序列化对象
1 2 3 4 5 6 7 8 var point = { x : 1 , y : { z : [false , null , "" ] } } s = JSON .stringify (point); p = JSON .parse (s);
#5. 数组
JavaScript数组是动态的额, 数组元素无类型(可以存放任意类型), 数组是对象的特殊形式
创建数组
1 2 3 4 5 var misc = [1.1 , true , "a" ,]; var undes = [,,]; var a = new Array (); var a = new Array (10 ); var a = new Array (1 , 2 , 3 , "test" );
数组的读取和写入
下标访问, 从零开始
通过var a = new Array(10); 可以创建稀疏数组
1 2 3 4 var a = [];a.push (5 ); a.pop (); delete a[0 ];
多维数组
使用数组的数组进行近似, 风格和访问与C++中类似
数组方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var a = [1, 2, 3]; a.join(); // 数组拼接, 默认使用,拼接成字符串, 是String.split的逆方法 a.reverse(); // 数组逆序 a.sort(); // 数组排序 a.concat([1, 2]); // 数组拼接, 返回新数组 a.slice(0, 2); // 数组切片 a.splice(删除起始位置[, 删除个数[, 插入元素]]); // 在数组中插入或删除元素 a.push(), a.pop(); // 数组模拟栈 a.unshift(), a.shift(); // 数组头部添加和删除元素 a.toString(); // 每个元素字符串化 /* ECMAScript 5数组方法 */ forEach(); // 从头到尾遍历数组, 为每个元素调用指定函数 map(); // 对每个元素调用指定元素, 并返回数组 filter(); // 返回满足函数逻辑的元素的数组(子集) every(), some(); // 对数组元素应用指定函数判定, 返回true或false reduce(操作函数[, 可选传递给操作函数的初始参数]) indexOf(), lastIndexOf(); // 搜索整个数组具有给定值的元素 Array.isArray([]); // true, 判断是否为数组
#6. 函数
函数即对象
函数定义
1 2 3 function funcname (参数 ) { }
函数length属性代表函数参数的数量
prototype属性
call()和apply()方法
bind()方法, 将一个函数绑定到对象中, 作为对象的方法
Function()构造函数, 可以传入任意数量的字符串实参, 最后一个实参表示的文本就是函数体(不能用来实现闭包), 匿名
1 2 3 4 5 f.call (o) f.apply (o) var f = new Function ("x" , "y" , "return x * y;" );
#7. 类和模块
JavaScript中类的实现基于原型继承机制, JavaScript中的类是动态可继承的
关键字new调用构造函数,自动创建一个新对象,构造函数的prototype属性被用作新对象的原型,构造函数对已创建的对象初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Range (from , to ) { this .from = from ; this .to = to; } Range .prototype = { constructor : Range , includes : function (x ) { return this .from <= x && x <= this .to ; }, foreach : function (f ) { for (var x = Math .ceil (this .from ); x <= this .to ; x++) f (x); }, toString : function ( ) { return "(" + this .from + "..." + this .to + ")" } }; var r = new Range (1 , 3 );
检测任意对象的类:
使用instanceof运算符
constructor属性(前两种方法在多个执行上下文场景中无法正常工作)
构造函数的名字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 var r = new Range (1 , 3 );r.constructor === Range function type (o ) { var t, c, n; if (o === null ) return "null" ; if (o !== o) return "nan" ; if ((t = typeof o) !== "object" ) return t; if ((c = classof (o)) !== "Object" ) return c; if (o.constructor && typeof o.constructor === "function" && (n = o.constructor .getName ())) return n; return "Object" ; } function classof (o ) { return Object .prototype .toString .call (o).slice (8 , -1 ); } Function .prototype .getName = function ( ) { if ("name" in this ) return this .name ; return this .name = this .toString ().match (/function\s*([^(]*)\(/ )[1 ]; }
子类
B是A的子类
1 2 B.prototype = inherit (A.prototype ); B.prototype .constructor = B;