JavaScript 入门
1. 概述
1.2 语言特性
1.2.1 动态性
:只需在使用时做赋值操作即可
var obj = new Object();
obj.name = "an object";
obj.sayHi = function() {
return "Hi";
}
obj.sayHi();
/*
输出结果:
< 'Hi'
*/
当不需要一个对象的属性时,
obj.name
/*
输出结果:
< 'an object'
*/
delete obj.name
/*
输出结果:
< true
*/
obj.name
/*
undefined
*/
另外一点,可以动态访问一个 JavaScript 对象的属性。
var key = "property";
console.log(key);
/*
输出结果:
< property
*/
var obj = {
property: "my property"
}
console.log(obj[key]);
/*
输出结果:
< my property
*/
1.2.2 弱类型
:数据类型无需在声明时指定,解释器会根据上下文对变量进行实例化。
var s = "text";
console.log(s);
/*
输出结果:
< text
*/
s = 12 + 5;
console.log(s);
/*
输出结果:
< 17
*/
s = 6.3;
console.log(s);
/*
输出结果:
< 6.3
*/
s = new Object();
s.name = "object";
console.log(s.name);
/*
输出结果:
< object
*/
1.2.3 面向对象
代码本身可以作为参数传递给其他的代码。
var array = [1, 2, 3, 4, 5];
array.map(function(item){
return item * 2;
});
/*
输出结果:
< [2, 4, 6, 8, 10]
*/
map 函数可以处理更复杂的场景,
var staff = [
{name: 'abruzzi', age: 24},
{name: 'bajmine', age: 26},
{name: 'chris', age: 25}
];
staff.map(function(item){
return item.name.toUpperCase();
});
/*
输出结果:
< ['ABRUZZI', 'BAJMINE', 'CHRIS']
*/
与 map 函数类似,filter 函数用于过滤数组中满足某些条件的元素,
var staff = [
{name: 'abruzzi', age: 24},
{name: 'bajmine', age: 26},
{name: 'chris', age: 25}
];
staff.filter(function(item){
return item.age > 24;
});
/*
输出结果:
< [
{name: 'bajmine', age: 26},
{name: 'chris', age: 25}
]
*/
1.3 应用范围
1.3.2 服务器端 JavaScript
node.js 的例子,
//ERROR
var sys = require('sys'),
http = require('http');
http.createServer(function(req, res){
setTimeout(function(){
res.sendHeader(200,{'Content-Type': 'text/plain'});
res.sendBody('Hello World');
res.finish();
},2000);
}).listen(8000);
sys.puts('Server running at http://127.0.0.1:8000/');
例子二,
//ERROR
var tcp = require('tcp');
var server = tcp.createServer(function(socket){
socket.setEncoding("utf-8");
socket.addListener("contect",function(){
socket.send("hello\r\n");
});
socket.addListener("receive",function(data){
socket.send(data);
});
socket.addListener("eof",function(){
socket.send("goodbye\r\n");
socket.close();
});
});
server.listen(7000,"localhost");
2. 基本概念
2.1 数据类型
2.1.1 数据类型
JavaScript 包含 6 种数据类型:字符串(string) 、数值(number)、布尔值(boolean)、未定义(undefined)、不存在(null)、对象(object)。
var str = "Hello";
var i = 10;
var f = 2.3;
var b = true;
console.log(str);
console.log(i);
console.log(f);
console.log(b);
console.warn(typeof str);
console.warn(typeof i);
console.warn(typeof f);
console.warn(typeof b);
console.warn(typeof x);
2.1.2 对象类型
对象类型是一种复合的数据类型,其基本元素有基本数据类型组成。
var str = "Hello";
var obj = new Object();
obj.str = str;
obj.num = 2.3;
var array = new Array("foo","bar","zoo");
var func = function(){
console.log("A function");
}
console.log(typeof obj); //> object
console.log(typeof array); //> object
console.log(typeof func); //> function
2.1.3 基本类型与对象间的转换
基本类型转换为对象类型的实例,
var str1 = "JavaScript Kernal";
console.log(str1.length); //> 17
console.log(typeof str1); //> string
var str2 = new String("JavaScript Kernal");
console.log(str2.length); //> 17
console.log(typeof str2); //> object
此时 str1 作为 string,与 object 完全不同,却都可以调用函数 str.length,说明在使用该函数时,JavaScript 会自动包装一个临时的 Sring 对象,内容为 str1 的内容,然后获取该对象的 length 属性,最后将这个临时对象释放。
而将对象转换为基本类型的方式为:通过调用对象的 valueOf() 方法来取得对象的值。如果取不到值,则需调用对象的 toString() 方法,必要时将该字符串值转换为数值。事实上这种转换存在许多问题,例如,
function convertTest(){
if(new Boolean(false) && new Object() && new String("") && new Array()){
console.log("convert to boolean")
}
}
convertTest(); //> convert to boolean
例子二,
var x = 3;
var y = x + "2";
var z = x + 2;
console.log(y); //> 32
console.log(z); //> 5
2.1.4 类型的判断
一般情况下,typeof 可以胜任大部分的类型判断工作,
function handleMessage(message, handle){
if(typeof handle == "function"){
return handle(message);
}else{
throw new Error("the 2nd argument should be a function");
}
}
但在以下情况中就会出现问题,
var obj = {};
var array = ["one","two"];
console.log(obj); //> object
console.log(array); //> object
此时,可以利用 instanceof 来进行下一步的判断,
var obj = {};
var array = ["one","two"];
console.log(obj instanceof Array); //> false
console.log(array instanceof Array); //> true
2.2 变量
2.2.1 基本类型和引用类型
区别:通过变量直接访问基本类型的数据;通过对其引用的访问来访问引用类型的本身。
//基本类型
var x = 1;
var y = x;
console.log(x + " " + y); //> 1 1
x = 2;
console.log(x + " " + y); //> 2 1
//引用类型
var array = [1, 2, 3, 4, 5];
var arrayRef = array;
array.push(6);
console.log(arrayRef); //> [1, 2, 3, 4, 5, 6]
2.2.2 变量的作用域
声明在函数内部的变量具有局部作用域,在函数的外部不可访问,
var variable = "out";
function func(){
var variable = "in";
console.log(variable); //> in
}
func();
console.log(variable); //> out
同时,在局部默认的操作会影响全局变量,
var variable = "out";
function func(){
variable = "in";
console.log(variable); //> in
}
func();
console.log(variable); //> in
2.3 运算符
2.3.1 中括号运算符
(一)数组对象,从数组中按下标取值。
var array = ["one", "two", "three", "four"];
array[0];
(二)对象
var object = {
field : "self",
printInfo : function(){
console.log(this.field);
}
}
object.field;
object.printInfo(); //> self
for (var key in object){
console.log(key + " : " + object[key]);
/*
*> field : self
*> printInfo : function(){
console.log(this.field);
}
*/
}
2.3.2 点运算符
对象 . (属性 / 对象)
var object = {
field : "self",
printInfo : function(){
console.log(this.field);
},
outter:{
inner : "inner text",
printInnerText : function(){
console.log(this.inner);
}
}
}
object.outter.printInnerText(); //> inner text
上述 Code 中,outter 既是 object 的属性,也是 printInnerText 的对象。
如果一个对象的属性本身就包含点的键(self.ref),此时点运算符就无用了。
var ref = {
id : "rerference1",
func : function() {
return this.id;
}
};
var obj = {
id : "object1",
"self.ref" : ref
};
console.log(obj["self.ref"].func()); //> reference1
2.3.3 相等于等同运算符
相等:==
等同:===
console.log(1 == true); //> true
console.log(1 === true); //> fasle
console.log("" == false); //> true
console.log("" === false); //> false
console.log(null == undefined); //> true
console.log(null === undefined); //> false
比如:
var obj = {
id : "self",
name : "object"
};
var oa = obj;
var ob = obj;
console.log(oa == ob); //> true
console.log(oa === ob); //> true
var obj1 = {
id : "self",
name : "object",
toString : function(){
return "object 1";
}
}
var obj2 = "object 1";
console.log(obj1 == obj2); //> true
console.log(obj1 === obj2); //> false
3. 对象
3.1 JavaScript 对象
3.1.1 对象的属性
//声明一个对象
var jack = new Object();
jack.name = "jack";
jack.age = 26;
jack.birthday = new Date(1984, 4, 5);
//声明另一个对象
var address = new Object();
address.street = "HQ Road";
address.xno = "135";
jack.addr = address;
console.log(jack);
var ja = jack.addr;
ja = jack["addr"];
console.log(ja);
3.1.2 属性与变量
JavaScript 引擎在初始化时,会构建一个全局对象;在客户端环境中,该全局对象即为 window。
如果在其他的 JavaScript 环境中需要引用这个全局对象,只需在顶级作用域(即所有函数声明之外的作用域)声明即可。
在客户端中,以下 Code
var v = "global";
var array = ["hello", "world"];
function func(id){
var element = document.getElementById(id);
}
事实上等于,
window.v = "global";
window.array = ["hello", "world"];
window.func = function(id){
var element = document.getElementById(id);
}
由此,变量就是全局对象(global)的属性。
3.1.3 原型对象及原型链
原型(prototype)是 JavaScript 特有的概念。通过使用原型,JavaScript 可以建立其对象面向对象语言中的继承。
JavaScript 本身是基于原型的,每个对象都有一个 prototype 属性,这个 prototype 本身也是一个对象,因此也有自己的原型,从而构成了一个链结构。
举例,
function Base(name){
this.name = name;
this.getName = function(){
return this.name;
}
}
function Child(id){
this.id = id;
this.getId = function(){
return this.id;
}
}
Child.prototype = new Base("base");
var c1 = new Child("child");
console.log(c1.getId()); //> child
console.log(c1.getName()); //> base
由于遍历原型链时,是由下而上的,所以最先遇到的属性值最先返回。
function Person(name, age){
this.name = name;
this.age = age;
this.getName = function(){
return this.name;
}
this.getAge = function(){
return this.age;
}
}
var tom = new Person("Tom", 38);
var jerry = new Person("Jerry", 6);
console.log(tom);
console.log(jerry.getName()+" "+jerry.getAge()); //> Jerry 6
3.1.4 this 指针
this 表示当前上下文(context),即对调用者的引用。
举例,
var jack = {
name : "jack",
age : 26
}
var abruzzi = {
name : "abruzzi",
age : 26
}
function showName(){
return this.name;
}
console.log(showName.call(jack)); //> jack
console.log(showName.call(abruzzi)); //> abruzzi
3.2 使用对象
定义对象的 “类”:原型,然后使用 new 操作符来批量构建新的对象。
function Address(street, xno){
this.street = street || 'HQ Road';
this.xno = xno || 135;
this.toString = function(){
return "street: " + this.street + ", No: " + this.xno;
}
}
function Person(name, age, addr){
this.name = name || 'unknown';
this.age = age;
this.addr = addr || new Address(null, null);
this.getName = function() { return this.name; }
this.getAge = function() { return this.age; }
this.getAddr = function() { return this.addr.toString(); }
}
var jack = new Person('jack', 26, new Address('QH Road', 123));
var abruzzi = new Person('abruzzi', 26);
console.log(jack.getName()); //> jack
console.log(jack.getAge()); //> 26
console.log(jack.getAddr()); //> street: QH Road, No: 123
console.log(abruzzi.getName()); //> abruzzi
console.log(abruzzi.getAge()); //> 26
console.log(abruzzi.getAddr()); //> street: HQ Road, No: 135
3.3 对象字面量
例如,
var obj = {
name : "abruzzi",
addr : {
street : "HQ Road",
xno : "135"
}
}
对于一个函数有多个返回值时,
function point(left, top){
this.left = left;
this.top = top;
return { x: this.left, y: this.top };
}
var pos = point(3, 4);
//pos.x = 3;
//pos.y = 4;
for...in 语法糖,
for(var item in json){
//item 为键
//json[item] 为值
}
在实际 Web 应用中,
var style = {
border : "1px solid #ccc",
color : "blue"
}
//添加 DOM 元素动态地添加这些属性:
for(var item in style){
//使用 jQuery 的选择器
$("div#element").css(item, style[item]);
}
另外,当需要用户自定义设置时,用户将需要设置的内容填入这个对象,
function customize(options){
this.default = {
width : 100,
height : 100,
background : '#ccc'
};
//jQuery 中的 extend 方法可以将两个对象的内容合并
this.setting = $.extend(this.default, options);
}
constomize({
background: '#6b6b6b'
});
this.setting = {
width : 100,
height : 100,
background : '#6b6b6b'
};
3.4 JSON
:前端与服务器端的数据交换的标准格式:
前端程序通过 Ajax 发送 JSON 到后端,服务器端脚本对 JSON 进行解析,还原成服务器端对象,经过处理,返回给前端的仍然是 JSON 数据。JSON 相对 XML 更高效,冗余更小。
一个典型的 JSON 格式的数据看起来是这样的:
{
"content":"make the index page more fancy of feather",
"complete":false
}
客户端组织这样的 JSON,通过 HTTP 发送给服务器端,服务器根据 JSON 解析器将其转换为服务器端对应的模型对象(如 Java 对象 / Ruby 对象),再进行数据库访问,创建完成后将结果转换为 JSON 格式返回给客户端。
{
"id": 1,
"content": "make the index page more fancy of feather",
"complete": false,
"created_at": "2012-01-24TH16:03:13+08:00",
"updated_at": "2012-01-24TH16:03:13+08:00",
"user_id": 1
}
4. 函数
4.1 函数对象
4.1.1 创建函数
通过字面量来创建函数,
function add(x, y){
return x + y;
}
//或
var add = function(x, y){
return x + y;
}
函数作为一个独立的对象而存在于 JavaScript 的运行系统,例如,
function p(){
console.log("invoke p by()");
}
p.id = "func";
p.type = "function";
console.log(p); /*> p(){
console.log("invoke p by()");
}
*/
console.log(p.id + ":" + p.type); //> func:function
console.log(p()); //> invoke p by()
4.1.2 函数的参数
任意多的参数传递给一个函数,比如,
function adPrint(str, len, option){
var s = str || "default";
var l = len || s.length;
var o = option || "i";
s = s.substring(0, l);
switch(o){
case "u":
s = s.toUpperCase();
break;
case "l":
s = s.toLowerCase();
break;
default:
break;
}
console.log(s);
}
adPrint("Hello, world"); //> Hello world
adPrint("Hello, world", 5); //> Hello
adPrint("Hello, world", 5, "l"); //> hello
adPrint("Hello, world", 5, "u"); //> HELLO
arguments 的例子,
function sum(){
var result = 0;
for(var i = 0, len = arguments.length; i < len; i++){
var current = arguments[i];
if(isNaN(current)){
throw new Error("not a number exception");
}else{
result += current;
}
}
return result;
}
console.log(sum(10, 20, 30, 40, 50)); //> 150
console.log(sum(4, 8, 15, 16, 23, 42)); //> 108
console.log(sum("new")); //> Error: not a number exception
4.2 函数作用域
4.2.1 词法作用域
JavaScript 中的变量作用域为函数体内有效,而无块作用域。
在 Java 中,
public void method(){
for(int i = 0; i < obj1.length; i++){
//do sth here
}
for(int i = 0; i < array.length; i++){
//do sth here
}
}
而在 JavaScript 中,
function func(){
for(var i = 0; i < array.length; i++){
//do sth here
}
console.log(i);
}
局部作用域内运行的函数体可以访问其外层的变量与函数,例如,
var str = "global";
function scopeTest(){
console.log(str); //> undefined
var str = "local"; //> local
console.log(str);
}
scopeTest();
4.2.2 调用对象
:在一个函数中,作用域链上会有两个对象,第一个(首先被访问到的)为调用对象(又称活动对象),第二个为全局对象。
4.3 函数上下文
4.4 call 和 apply
:call 和 apply 通常用来修改函数上下文。
举例,
var jack = {
name : "jack",
age : 26
}
var abruzzi = {
name : "abruzzi",
age : 26
}
function printName(){
return this.name;
}
//设置 printName 的上下文为 jack,此时的 this 为 jack
console.log(printName.call(jack)); //> jack
//设置 printName 的上下文为 abruzzi,此时的 this 为 abruzzi
console.log(printName.call(abruzzi)); //> abruzzi
console.log(printName.apply(jack)); //> jack
console.log(printName.apply(abruzzi)); //> abruzzi
只有一个参数时 call 与 apply 的使用方式相同,当有多个参数时,
setName.apply(jack, ["Jack Sept."]);
console.log(printName.apply(jack));
setName.call(abruzzi, "John Abruzzi");
console.log(printName.call(abruzzi));
4.5 使用函数
4.5.1 赋值给一个变量
function add(x, y){
return x + y;
}
var a = 0;
a = add;
var b = a(2, 3);
console.log(b); //> 5
4.5.2 赋值为对象的属性
var obj = {
id : "obj1"
}
obj.func = add;
obj.func(2, 3); //> 5
4.5.3作为参数传递
function adPrint2(str, handler){
console.log(handler(str));
}
function up(str){
return str.toUpperCase();
}
function low(str){
return str.toLowerCase();
}
adPrint2("Hello, world", up); //> HELLO,WORLD
adPrint2("Hello, world", low); //> hello, world
4.5.4 作为函数的返回值
function currying(){
return function(){
console.log("curring");
}
}
currying()(); //> curring
5. 数组
数组对象的方法
方法 | 描述 |
---|---|
concat() | 连接连个以上的数组,并返回结果数组 |
join() | 把数组的所有元素放入一个字符串 |
pop() | 删除并返回数组的最后一个元素 |
push() | 向数组的末尾添加元素,并返回新的长度 |
reverse() | 翻转数组中的元素顺序 |
shift() | 删除并返回数组的第一个元素 |
slice() | 从某个已有的数组返回选定的元素 |
sort() | 对数组中的元素进行排序 |
splice() | 删除元素,并向数组添加新元素 |
unshift() | 向数组的开头添加元素,并返回新的长度 |
valueOf() | 返回数组对象的原始值 |
5.1 数组的特性
(一)length 这个变量并非只读属性,
var array = new Array(1, 2, 3, 4, 5);
console.log(array.length); //> 5
array.length = 3;
console.log(array.length); //> 3
console.log(array); //> [1, 2, 3]
(二)字符串也可以作为数组的下标
var stack = new Array();
stack['first'] = 3.1415926;
stack['second'] = "okay then.";
stack['third'] = new Date();
for(var item in stack){
console.log(typeof stack[item]);
}
/*
输出结果:
number
string
object
*/
5.2 使用数组
5.2.1 数组的基本方法使用
//创建数组
var array = [];
//向数组中添加元素
array.push(1);
array.push(2);
array.push(3);
array.push("four");
array.push("five");
array.push(3.1415926);
//弹出数组中的元素
var len = array.length;
for(var i = 0; i < len; i++){
console.log(typeof array[i] + ": " + array.pop());
}
console.log("Length: " + array.length); //> Length: 0
//join,连接数组元素为一个字符串
array = ["one", "two", "three", "four", "five"];
var str1 = array.join(",");
var str2 = array.join("|");
console.log(str1); //> one,two,three,four,five
console.log(str2); //> one|two|three|four|five
//连接多个数组为一个数组
var another1 = ["this", "is", "another", "array"];
var another2 = ["yet", "another", "array"];
var bigArray = array.concat(another1, another2);
console.log(bigArray.join(","));
//> one,two,three,four,five,this,is,another,array,yet,another,array
//取出一定数量的元素
console.log(bigArray.slice(5,9)); //> ['this', 'is', 'another', 'array']
//splice 方法
bigArray.splice(5, 2); //自第 5 个元素起,删除 2 个元素
console.log(bigArray);
//自第 5 个元素起,删除 0 个元素,并在第 5 个元素后插入新的参数
bigArray.splice(5, 0, "very", "new", "item", "here");
console.log(bigArray);
//sort 方法对数组进行排序
var arraySort = ["Cisio", "Borland", "Apple", "Dell"];
console.log(arraySort); //> ['Cisio', 'Borland', 'Apple', 'Dell']
arraySort.sort();
console.log(arraySort); //> ['Apple', 'Borland', 'Cisio', 'Dell']
arraySort = [11, 222, 3333, 4444];
arraySort.sort(function(a, b){ return a-b; }) //正序
console.log(arraySort); //> [11, 222, 3333, 4444]
arraySort.sort(function(a, b){ return b-a; }) //逆序
console.log(arraySort); //> [4444, 3333, 222, 11]
5.2.2 删除数组元素
delete 方法可以删除元素的内容,
var array = ["one", "two", "three", "four"];
console.log(array); //> ['one', 'two', 'three', 'four']
delete array[2];
console.log(array); //> ['one', 'two', empty, 'four']
利用 jQuery 中的 remove 方法可以删除数组的元素,
var array = ["one", "two", "three", "four", "five", "six"];
console.log(array);
array.remove(0); //删除第一个元素
console.log(array);
array.remove(-1); //删除最后一个元素
console.log(array);
array.remove(0, 2); //删除数组中下标为 0~2 的元素
console.log(array);
5.2.3 遍历数组
var array = [1, 2, 3, 4];
for(var item in array){
console.log(array[item]);
}
但 for...in 方法不总是有效,例如,
Array.prototype.useless = function(){}
这时,应考虑使用 for 循环,例如,
var array = [1, 2, 3];
for(var i = 0; i < array.length; i++){
console.log(array[i]);
}
6. 正则表达式
6.1 基础概念
6.1.1 元字符与特殊字符
元字符 | 含义 |
---|---|
^ | 串的开始 |
$ | 串的结束 |
* | 零到多次匹配 |
+ | 一到多次匹配 |
? | 零或一次匹配 |
\b | 单词边界 |
字符 | 含义 |
---|---|
字符本身 | 匹配字符本身 |
\r | 匹配回车 |
\n | 匹配换行 |
\t | 制表符 |
\f | 换页 |
\x# | 匹配十六进制数 |
\cX | 匹配控制字符 |
6.1.2 范围及重复
标识符 | 含义 |
---|---|
[...] | 在集合中的任一个字符 |
[^...] | 不在集合中的任一个字符 |
. | 除\n之外的任一个字符 |
\w | 所有的单字,包括字母,数字及下划线 |
\W | 不包括所有的单字 |
\s | 所有的空白字符,包括空格与制表符 |
\S | 所有的非空白字符 |
\d | 所有的数字 |
\D | 所有的非数字 |
\b | 退格字符 |
var emailval = /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/;
emailval.test("abcd@gmail.com"); //> true
emailval.test("john.abruzzi@pl.kunming.china"); //> true
emailval.test("@invalid.com"); //> false
对 C/C++/Java 语言中的变量命名检查,
var variable = /^[a-zA-z_][a-zA-z0-9_]*$/;
console.log(variable.test("hello")); //> true
console.log(variable.test("g00le")); //> true
console.log(variable.test("_abcd")); //> true
console.log(variable.test("o8179")); //> true
console.log(variable.test("08179")); //> false
console.log(variable.test("8_h_w")); //> false
console.log(variable.test("@_h_w")); //> false
正则表达式的重复
标记 | 含义 |
---|---|
重复 n 次 | |
重复 n 或更多次 | |
重复至少 n 次,m 次 |
var pid = /^[\d{15}|\d{18}]$/; //身份证号码
var mphone = /\d{11}/; //手机号码
var phone = /\d{3,4}-\d{7,8}/; //座机号码
console.log(pid.test("210211200001015623")); //> false ???
console.log(mphone.test("13545689000")); //> true
console.log(phone.test("010-99392333")); //> true
console.log(phone.test("0791-88650279")); //> true
6.1.3 分组与引用
(一)括号用来将子表达式标记起来,以区别于其他表达式,如,
h(elp)? //字符 h 之后的 elp 可有可无
(二)分组,如,
var pattern = /\w{4}(\d{4})(\w{2})/;
var result = pattern.exec("yunn0871cg");
console.log("city code = " + result[1] + ", county code = " + result[2]);
//> city code = 0871, county code = cg
result = pattern.exec("shax0917cc");
console.log("city code = " + result[1] + ", county code = " + result[2]);
//> city code = 0917, county code = cc
(三)对引用起辅助作用,如,...
6.2 使用正则表达式
6.2.1 创建正则表达式
使用字面量,
var regex = /pattern/;
使用 RegExp 对象,
var regex = new RegExp("pattern", switchs);
正则表达式的一般形式描述为,
var regex = /pattern/[switchs];
这里的开关(switchs)有以下三种,
修饰符 | 描述 | 举例 |
---|---|---|
i | 忽略大小写开关 | /java/i可以匹配java/Java/JAVA |
g | 全局搜索开关 | /java/g匹配"javascript&java"中的两个"java" |
m | 多行搜索开关(重定义 ^ 与 $ 的意义) | Code 如下 |
var pattern = /^javascript/;
console.log(pattern.test("java\njavascript")); //> false
pattern = /^javascript/m;
console.log(pattern.test("java\njavascript")); //> true
RegExp 对象的方法,
方法名 | 描述 | 使用方式 |
---|---|---|
test() | 测试串中是否有合乎模式的匹配 | 测试 |
exec() | 对串进行匹配 | 分组 |
cpmpile() | 编译正则表达式 | 改变表达式模式 |
6.2.2 String 中的正则表达式
String 对象中的正则表达式
方法 | 作用 |
---|---|
match | 匹配正则表达式,返回匹配数组 |
replace | 替换 |
split | 分割 |
search | 查找,返回首次发现的位置 |
match 举例,
var str = "life is very much like a mirror.";
var result = str.match(/is|a/g);
console.log(result); //> ['is', 'a']
replace 举例,
var str = "<span>Welcome</span>";
var res = str.replace(/span/g, "div");
console.log(str); //> <span>Welcome</span>
console.log(res); //> <div>Welcome</div>
var str = "<span>abc, bcd</span>";
var res = str.replace(/(\w+),\s(\w+)/g, "$2, $1");
console.log(str); //> <span>abc, bcd</span>
console.log(res); //> <span>bcd, abc</span>
split 举例,
var str = "john : tomorrow :remove:file";
var res = str.split(/\s*:\s*/);
console.log(str); //> john : tomorrow :remove:file
console.log(res); //> ['john', 'tomorrow', 'remove', 'file']
search 举例,
var str = "Tomorrow is another day";
var index = str.search(/another/);
console.log(index); //> 12
7. 闭包
7.1 闭包的特性
var outter = [];
function clouseTest(){
var array = ["one", "two", "three", "four"];
for(var i = 0; i < array.length; i++){
var x = {};
x.no = i;
x.text = array[i];
x.invoke = function(){
console.log(i);
}
outter.push(x);
}
}
clouseTest();
console.log(outter[0].invoke()); //> 4
console.log(outter[1].invoke()); //> 4
console.log(outter[2].invoke()); //> 4
console.log(outter[3].invoke()); //> 4
理论上,输出内容应为 0 1 2 3
实际上输出内容为 4 4 4 4
为解决上述问题,可声明一个匿名函数,Code 如下,
var outter = [];
function clouseTest2() {
var array = ["one", "two", "three", "four"];
for(var i = 0; i < array.length; i++){
var x = {};
x.no = i;
x.text = array[i];
x.invoke = function(no){
return function(){
console.log(no);
}
}(i);
outter.push(x);
}
}
clouseTest2();
console.log(outter[0].invoke()); //> 0
console.log(outter[1].invoke()); //> 1
console.log(outter[2].invoke()); //> 2
console.log(outter[3].invoke()); //> 3
7.2 闭包的用途
7.2.1 匿名自执行函数...
var datamodel = {
table : {},
tree : {}
};
(function(dm){
for(var i = 0; i < dm.table.rows; i++){
var row = dm.table.rows[i];
for(var j = 0; j < row.cells; i++){
drawCell(i, j);
}
}
//build dm.tree
})(datamodel);
7.2.2 缓存...
var CacheSearchBox = (function(){
var cache = {},
count = [];
return {
attachSearchBox : function(dsid){
if(dsid in cache){
return cache[dsid];
}
var fsb = new uikit.webctrl.SearchBox(dsid);
cache[dsid] = fsb;
if(count.length > 100){
delete cache[count.shift()];
}
return fsb;
},
clearSearchBox : function(dsid){
if(dsid in cache){
cache[dsid].clearSelection();
}
}
};
})();
CachedSearchBox.attachSearchBox("input1");
7.2.3 实现封装
(一)在 person 之外的地方无法访问其内部变量,可以提供闭包的形式来访问。
var person = function(){
var name = "default";
return {
getName : function(){
return name;
},
setName : function(newName){
name = newName;
}
}
}();
console.log(person.name); //> undefined
console.log(person.getName()); //> default
person.setName("abruzzi");
console.log(person.getName()); //> abruzzi
(二)实现面向对象中的对象。
function Person(){
var name = "default";
return {
getName : function(){
return name;
},
setName : function(newName){
name = newName;
}
}
};
var john = Person();
console.log(john.getName()); //> default
john.setName("john");
console.log(john.getName()); //> john
var jack = Person();
console.log(jack.getName()); //> default
jack.setName("jack");
console.log(jack.getName()); //> jack
7.面向对象的 JavaScript
7.1 原型继承
JavaScript 的继承可以通过原型链来实现,调用对象的上一个方法。
举例,
//ERROR
function Base(){
this.baseFunc = function(){
console.log("base behavior");
}
}
function Middle(){
this.middleFunc = function(){
console.log("middle behavior");
}
}
Middle.prototype = new Base();
function Final(){
this.finalFunc = function(){
console.log("final behavior");
}
}
Final.prototype = new Middle();
function test(){
var obj = new Final();
obj.baseFunc();
obj.middleFunc();
obj.finalFunc();
}
7.1.1 引用
JavaScript 中的引用始终指向最终的对象,并非引用本身,举例,
var obj = {};
var ref = obj;
obj.name = "objectA";
console.log(ref.name); //> objectA
obj = ["one", "two", "three", "four"];
console.log(ref.name); //> objectA
console.log(obj.length); //> 4
console.log(ref.length); //> undefined
在定义了引用后,修改原始的那个对象会影响到其引用上,举例,
var obj = {};
var ref1 = obj;
var ref2 = obj;
obj.func = "function";
console.log(ref1.func); //> function
console.log(ref2.func); //> function
7.1.2 new 操作符
纠正 Java 程序员对 new 操作符的固有认知,举例,
function Shape(type){
this.type = type || "rect";
this.calc = function(){
return "calc, " + this.type;
}
}
var triangle = new Shape("triangle");
console.log(triangle.calc()); //> calc, triangle
var circle = new Shape("circle");
console.log(circle.calc()); //> calc, circle
在 JavaScript 中,通过 new 操作符来作用于一个函数,举例,
function Shape(type){
this.type = type || "rect";
this.calc = function(){
return "calc, " + this.type;
}
}
var triangle = new Shape("triangle");
var triangle = {};
Shape.apply(triangle, ["triangle"]);
7.2 封装
封装的好处在于未经授权的客户代码无法访问到我们不公开的数据,举例,
function Person(name){
var address = "The Earth";
this.getAddress = function(){
return address;
}
this.name = name;
}
Person.prototype.getName = function(){
return this.name;
}
Person.prototype.setName = function(name){
this.name = name;
}
var jack = new Person("jack");
console.log(jack.name); //> jack
console.log(jack.getName()); //> jack
console.log(jack.address); //> undefined
console.log(jack.getAddress()); //> The Earth
也可以为类添加静态成员,比如,
function Person(name){
var address = "The Earth";
this.getAddress = function(){
return address;
}
this.name = name;
}
Person.TAG = "javascript-core";
console.log(Person.TAG); //> javascript-core
7.3 工具包 Base
假设我们在开发一个任务系统,需要抽象出一个类来表示任务,对应的,每个任务都可能会有一个监听器,Code 如下,
//ERROR
//首先定义一个事件监听类
var EventListener = Base.extend({
constructor : function(sense){
this.sense = sense;
},
sense : null,
handle : function(){
console.log(this.sense + " occured");
}
});
//然后定义一个任务类
var Task = Base.extend({
constructor : function(name){
this.name = name;
},
name : null,
listener : null,
execute : function(){
console.log(this.name);
this.listener.handle();
},
setListener : function(listener){
this.listener = listener;
}
});
var printing = new Task("printing");
var printEventListener = new EventListener("printing");
printing.setListener(printEventListener);
printing.execute();
var HttpRequester = Task.extend({
constructor : function(name, host, port){
this.base(name);
this.host = host;
this.port = port;
},
host : "127.0.0.1",
port : 9527,
execute : function(){
console.log("[" + this.name + "] request send to " + this.host + " of port " +this.port);
this.listener.handle();
}
});
var requester = new HttpRequester("requester1", "127.0.0.1", 8752);
var listener = new EventListener("http_request");
requester.setListener(listener);
requester.execute();
8. 函数式的 JavaScript
关于函数可以保持自己内部的数据这一特性,称为闭包。举例,
var outter = function(){
var x = 0;
return function(){
return x++;
}
}
var a = outter();
console.log(a());
console.log(a()); //> 0
var b = outter(); //> 1
console.log(b()); //> 0
console.log(b()); //> 1
8.1 匿名函数
:函数不被赋予名字
function func(){
//do something
}
var func = function(){
//do something
}
8.2 高阶函数
:以一个或多个函数为参数的函数称为高阶函数。
8.2.1 JavaScript 中的高阶函数...
Array.prototype.map = function(func /*, obj */){
var len = this.length;
if(typeof func != "function"){
throw new Error("argument should be a function!");
}
var res = [];
var obj = argument[1];
for(var i = 0; i < len; i++){
res[i] = func.call(obj, this[i], i, this);
}
return res;
}
function double(x){
return x * 2;
}
[1, 2, 3, 4, 5].map(double);
[
{id : "item1"},
{id : "item2"},
{id : "item3"}
].map(function(current){
console.log(current.id);
});
8.2.2 C 语言中的高阶函数
以 map 为例,
//函数原型
void map(int* array, int length, int (*func)(int));
map 的实现,
void map(int* array, int length, int (*func)(int)){
int i = 0;
for (i = 0; i < length; i++){
array[i] = func(array[i]);
}
}
由此进行以下测试,
#include<stdio.h>
int twice(int num){ return num * 2; }
int triple(int num){ return num * 3; }
void map(int* array, int length, int (*func)(int)){
int i = 0;
for (i = 0; i < length; i++){
array[i] = func(array[i]);
}
}
int main(int argc, char** argv){
int array[5] = {1, 2, 3, 4, 5};
int i = 0;
int len = 5;
printArray(array, len);
map(array, len, twice);
printArray(array, len);
map(array, len, triple);
printArray(array, len);
return 0;
}
8.2.3 Java 中的高阶函数
interface Function{
int execute(int x);
}
private int[] array;
public List(int[] array){
this.array = array;
}
public void map(Function func){
for(int i = 0, len = this.array.length; i < len; i++){
this.array[i] = func.execute(this.array[i]);
}
}
public static void main(String[] args){
List list = new List(new int[]{1, 2, 3, 4, 5});
list.print();
list.map(new Function(){
public int execute(int x){
return x * 2;
}
});
list.print();
list.map(new Function(){
public int execute(int x){
return x * 3;
}
});
list.print();
}
8.3 闭包与柯里化
8.3.1 柯里化概念
柯里化就是预先将函数的某些参数传入,得到一个简单的函数,但预先传入的参数被保存在闭包里。比如,
var adder = function(num){
return function(y){
return num + y;
}
}
var inc = adder(1);
var dec = adder(-1);
console.log(inc(99)); //> 100
console.log(dec(101)); //> 100
console.log(adder(100)(2)); //> 102
console.log(adder(2)(100)); //> 102
8.3.2 柯里化应用
页面元素局部刷新,举例,
function update(item){
return function(text){
$("div#" + item).html(text);
}
}
function refresh(url, callback){
var params = {
type : "echo",
data : ""
};
$.ajax({
type : "post",
url : url,
cache : false,
async : true,
dataType : "json",
data : params,
success : function(data, status){
callback(data);
},
error : function(err){
alert("error: " + err);
}
});
}
refresh("action.do?target=news", update("newsPanel"));
refresh("action.do?target=article", update("articlePanel"));
refresh("action.do?target=picture", update("picturePanel"));
8.4 举例
8.4.1 函数式编程风格
function great(a, b){ return a > b; }
function mul(a, b){ return a * b; }
function inc(a){ return a + 1; }
function factorial(n){
function fact_iter(product, counter, max){
if(great(counter, max)){
return product;
}else{
fact_iter(mul(counter, product), inc(counter), max);
}
}
return fact_iter(1, 1, n);
}
factorial(10);
上述 Code 还算不上完全具有函数式编程风格,改进如下,
function great(a, b){ return a > b; }
function mul(a, b){ return a * b; }
function inc(a){ return a + 1; }
function factorial(n){
return (function factiter(product, counter, max){
if(great(counter, max)){
return product;
}else{
factiter(mul(counter, product), inc(counter), max);
}
})(1, 1, n);
}
factorial(10);
8.4.2 Y-结合子
:便于递归匿名函数,以阶乘计算为例,
Y-结合子,
var Y = function(f){
return (function(g){
return g(g);
})(function(h){
return function(){
return f(h(h)).apply(null, argument);
};
});
};
接下来运用 Y-结合子,
var factorial = Y(function(func){
return function(x){
return x == 0 ? 1 : x * func(x - 1);
}
});
factorial(10);
或者,
Y(function(func){
return function(x){
return x == 0 ? 1 : x * func(x - 1);
}
})(10);
以上 Code,在 JavaScript 可化简为,
var fact = function(x){
return x == 0 ? 1 : x * arguments.callee(x - 1);
}
fact(10);
或者,
(function(x){
return x == 0 ? 1 : x * arguments.callee(x - 1);
})(10); //> 3628800
8.4.3 其他
//WRONG
function abs(x) { return x > 0 ? x : -x; }
function add(a, b){ return a + b; }
function sub(a, b){ return a - b; }
function div(a, b){ return a - b; }
function less(a, b){ return a < b; }
//函数的不动点
function fixedPoint(fx, first){
var tolerance = 0.00001;
function closeEnough(x, y){
return less( abs( sub(x, y) ), tolerance);
};
function Try(guess){
var next = fx(guess);
if(closeEnough(guess, next)){
return next;
}else{
return Try(next);
}
};
return Try(first);
}
//数层嵌套函数
function sqrt(x){
return fixedPoint(
function(y){
return function(a, b){ return div(add(a, b), 2); }(y, div(x, y));
},
1.0);
}
console.log(sqrt(100));
编辑于 2022/9/11
End