JavaScript学习笔记
1.六种数据类型
原始类型:
number
string
boolean
null
undefined
对象类型:
object
2.隐式转换
"37" - 7 // 30
"37" + 7 // 377
3.包装对象
var str = "string"; // 基本类型
// 为什么基本类型变量,可以使用length方法呢?
// 这里js会把str包装成对象变量,调用完length方法后,把临时对象销毁掉。
a.length;
4.类型检测
typeof:适合基本类型及function检测,遇到null失效。可以使用obj === null 来判断。
instanceof:适合自定义对象,也可以用来检测原生对象,在不同iframe和window间检测时失效。
Object.prototype.toString
constructor
duck type
5.表达式
6.运算符
一元运算符: +num
二元运算符: a + b
三元运算符: c ? a : b
特殊运算符:
条件运算符: c ? a : b
逗号运算符: a,b
delete: delete obj.x
in: "document" in window
instanceof: obj instanceof Func
new: new ClassName()
this: return this;
typeof: typeof 100;
void: void(0)
7.语句,严格模式
7.1 block块语句: {}
注意:没有块级作用域 eg:for循环中的i变量在外部也可以访问。
7.2 声明语句: var a = 1;
注意:var a = b = 1;会隐式把b变成全局变量,最好写成var a = 1, b = 1;
7.3 try catch语句:
try{
}catch(ex){
}
7.4 function语句:
// 函数声明,会预先声明,可以在函数定义前调用都可以的。
function fd() {
return true;
}
// 函数表达式
var fe = function(){
}
7.5 switch语句
switch(val){
case 1:
// do sth
break;
default:
// do sth
break;
}
7.6 严格模式:是一种特殊的运行模式,它修复了部分语言上的不足,提供更强的错误检查,并增强安全性。
function func() {
'use strict'; // 关键字,进行严格模式
}
8.对象
对象的属性是无序的
对象的属性的key值是字符串
8.1创建对象,原型链
// 第一种方法
var obj1 = {x:1,y:2};
// 第二种方法
function foo(){}
foo.prototype.z = 3;
var obj = new foo();
obj.x = 1;
obj.y = 2;
obj.x; // 1
obj.y; // 2
obj.z; // 3
typeof obj.toString; // 'function'
'z' in obj; // true
obj.hasOwnProperty('z'); // false
// 第三种方法
var obj = Object.create({x:1});
8.2读写对象属性
8.2.1属性读写
var obj = {x:1,y:2};
// 第一种方法
obj.x;
// 第二种方法
obj["y"];
// 第三种方法,注意:使用in关键字,可能会把原型链上的属性也获取出来,而且顺序是不确定的。
var p;
for(p in obj){
console.log(obj[p]);
}
8.2.2getter/setter方法
var man = {
name : 'Bosn',
weibo : '@Bosn',
get age() {
return new Date().getFullYear() - 1988;
},
set age(val) {
console.log('Age can\'t be set to ' + val);
}
}
console.log(man.age); // 27
man.age = 100; // Age can't be set to 100
console.log(man.age); // still 27
8.3属性标签
// 1.获取属性标签
Object.getOwnPropertyDescriptor({pro:true},"pro");
// 2.定义单个属性标签
var person = {};
Object.defineProperty(person,'name',{
configurable:false, // 表示是否可以修改
writable:false, // 表示是否可以重写
enumerable:true, // 表示是否可以枚举
value:"mike"
});
person.name; // mike
person.name = "Tim";
person.name; // still mike
delete person.name; // false
// 3.定义多个属性标签
Object.defineProperties(person,{
title: {value: "test", enumerable:true},
salary: {value: 50000, enumerable:true, writable:true}
});
8.4对象标签
8.4.1.__proto__原型标签
8.4.2.class标签
var toString = Object.prototype.toString;
function getType(o){return toString.call(o).slice(8,-1);};
toString.call(null); // "[object Null]"
getType(null); // "Null"
getType(undefined); // "Undefined"
getType(1); // "Number"
getType(new Number(1)); // "Number"
typeof new Number(1); // "object"
getType(true); // "Boolean"
getType(new Boolean(true)); // "Boolean"
8.4.3.extensible标签
var obj = {x : 1, y : 2};
Object.isExtensible(obj); // true
Object.preventExtensions(obj);
Object.isExtensible(obj); // false
obj.z = 1;
obj.z; // undefined, add new property failed
Object.getOwnPropertyDescriptor(obj, 'x');
// Object {value: 1, writable: true, enumerable: true, configurable: true}
Object.seal(obj);
Object.getOwnPropertyDescriptor(obj, 'x');
// Object {value: 1, writable: true, enumerable: true, configurable: false}
Object.isSealed(obj); // true
Object.freeze(obj);
Object.getOwnPropertyDescriptor(obj, 'x');
// Object {value: 1, writable: false, enumerable: true, configurable: false}
Object.isFrozen(obj); // true
// [caution] not affects prototype chain!!!
8.5序列化,其他对象方法
8.5.1自定义序列化
var obj = {
x : 1,
y : 2,
o : {
o1 : 1,
o2 : 2,
// key值必须为toJSON
toJSON : function () {
return this.o1 + this.o2;
}
}
};
JSON.stringify(obj); // "{"x":1,"y":2,"o":3}"
8.5.2其他对象方法
var obj = {x : 1, y : 2};
obj.toString(); // "[object Object]"
obj.toString = function() {return this.x + this.y};
"Result " + obj; // "Result 3", by toString
+obj; // 3, from toString
obj.valueOf = function() {return this.x + this.y + 100;};
+obj; // 103, from valueOf
"Result " + obj; // still "Result 3"
9.数组
JS的数组是弱类型的,数组中可以含有不同类型的元素。
9.1 创建数组
// 1.创建数组第一种方式
var arr = [1,true,null,undefined,{x:1},[1,2,3]];
// 2.创建数组第二种方式
var arr = new Array(true,false,null,1,2,"hi");
9.2 数组迭代
Array.prototype.x = 'inherited';
for(i in arr) {
console.log(arr[i]); // 1, 2, 3, 4, 5, inherited
}
for(i in arr) {
if (arr.hasOwnProperty(i)) {
console.log(arr[i]); // 1, 2, 3, 4, 5
}
}
9.3 二维数组,稀疏数组
// 二维数组
var arr = [[0,1],[2,3],[4,5]];
var i = 0, j = 0;
var row;
for (; i < arr.length; i++) {
row = arr[i];
console.log('row ' + i);
for (j = 0; j < row.length; j++) {
console.log(row[j]);
}
}
// 稀疏数组并不含有从0开始的连续索引。一般length属性值比实际元素个数大
var arr1 = [undefined];
var arr2 = new Array(1);
0 in arr1; // true
0 in arr2; // false
arr1.length = 100;
arr1[99] = 123;
99 in arr1; // true
98 in arr1; // false
var arr = [,,];
0 in arr; // false
9.4 数组方法
9.4.1 Array.prototype.join --> 将数组转换为字符串
var arr = [1, 2, 3];
arr.join(); // "1,2,3"
arr.join("_"); // "1_2_3"
function repeatString(str, n) {
return new Array(n + 1).join(str);
}
repeatString("a", 3); // "aaa"
repeatString("Hi", 5); // "HiHiHiHiHi"
9.4.2 Array.prototype.reverse --> 将数组逆序
var arr = [1, 2, 3];
arr.reverse(); // [3, 2, 1]
arr; // [3, 2, 1] 原数组会被修改
9.4.3 Array.prototype.sort --> 排序
var arr = ["a", "d", "c", "b"];
arr.sort(); // ["a", "b", "c", "d"]
arr = [13, 24, 51, 3]; // 会把数字转换成字符串再进行比较,而不是按照数字排序
arr.sort(); // [13, 24, 3, 51]
arr; // [13, 24, 3, 51] 原数组被修改
arr.sort(function(a, b) {
return a - b;
}); // [3, 13, 24, 51]
arr = [{age : 25}, {age : 39}, {age : 99}];
arr.sort(function(a, b) {
return a.age - b.age;
});
arr.forEach(function(item) {
console.log('age', item.age);
});
// result:
// age 25
// age 39
// age 99
9.4.4 Array.prototype.concat --> 数组合并
var arr = [1, 2, 3];
arr.concat(4, 5); // [1, 2, 3, 4, 5]
arr; // [1, 2, 3] 原数组未被修改
arr.concat([10, 11], 13); // [1, 2, 3, 10, 11, 13]
arr.concat([1, [2, 3]]); // [1, 2, 3, 1, [2, 3]]
9.4.5 Array.prototype.slice --> 返回部分数组
var arr = [1, 2, 3, 4, 5];
arr.slice(1, 3); // [2, 3] 原数组未被修改
arr.slice(1); // [2, 3, 4, 5]
arr.slice(1, -1); // [2, 3, 4]
arr.slice(-4, -3); // [2]
9.4.6 Array.prototype.splice --> 数组拼接
var arr = [1, 2, 3, 4, 5];
arr.splice(2); // returns [3, 4, 5]
arr; // [1, 2]; 原数组被修改
arr = [1, 2, 3, 4, 5];
arr.splice(2, 2); // returns [3, 4]
arr; // [1, 2, 5];
arr = [1, 2, 3, 4, 5];
arr.splice(1, 1, 'a', 'b'); // returns [2]
arr; // [1, "a", "b", 3, 4, 5]
9.4.7 Array.prototype.forEach --> 数组遍历
var arr = [1, 2, 3, 4, 5];
arr.forEach(function(x, index, a){
console.log(x + '|' + index + '|' + (a === arr));
});
// 1|0|true
// 2|1|true
// 3|2|true
// 4|3|true
// 5|4|true
9.4.8 Array.prototype.map --> 数组映射
var arr = [1, 2, 3];
arr.map(function(x) {
return x + 10;
}); // [11, 12, 13]
arr; // [1, 2, 3] 数组未被修改
9.4.9 Array.prototype.filter --> 数组过滤
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.filter(function(x, index) {
return index % 3 === 0 || x >= 8;
}); // returns [1, 4, 7, 8, 9, 10]
arr; // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 原数组未被修改
9.4.10 Array.prototype.every & some --> 数组判断
var arr = [1, 2, 3, 4, 5];
// 每个元素都要满足
arr.every(function(x) {
return x < 10;
}); // true
arr.every(function(x) {
return x < 3;
}); // false
var arr = [1, 2, 3, 4, 5];
// 有一个元素满足即可
arr.some(function(x) {
return x === 3;
}); // true
arr.some(function(x) {
return x === 100;
}); // false
9.4.11 Array.prototype.reduce&reduceRight --> 把数组元素聚合成一个结果
var arr = [1, 2, 3];
var sum = arr.reduce(function(x, y) {
return x + y
}, 0); // 6
arr; //[1, 2, 3] 原数组未被修改
arr = [3, 9, 6];
var max = arr.reduce(function(x, y) {
console.log(x + "|" + y);
return x > y ? x : y;
});
// 3|9
// 9|6
max; // 9
// 从右边可以
max = arr.reduceRight(function(x, y) {
console.log(x + "|" + y);
return x > y ? x : y;
});
// 6|9
// 9|3
max; // 9
9.4.12 Array.prototype.indexOf&lastIndexOf --> 数组检索
var arr = [1, 2, 3, 2, 1];
arr.indexOf(2); // 1
arr.indexOf(99); // -1
arr.indexOf(1, 1); // 4
arr.indexOf(1, -3); // 4
arr.indexOf(2, -1); // -1
arr.lastIndexOf(2); // 3
arr.lastIndexOf(2, -2); // 3
arr.lastIndexOf(2, -3); // 1
9.4.13 Array.isArray --> 判断是否有数组
Array.isArray([]); // true
[] instanceof Array; // true
({}).toString.apply([]) === '[object Array]'; // true
[].constructor === Array; // true
小结:
1.数组 VS 一般对象
相同点:
都可以继承
数组是对象,对象不一定是数组
都可以当做对象添加删除属性
不同点:
数组自动更新length
按索引访问数组常常比访问一般对象属性明显迅速。
数组对象继承Array.prototype上的大量数组操作方法
2.数组 VS 字符串
var str = "hello world";
str.charAt(0); // "h"
str[1]; // e
Array.prototype.join.call(str, "_");
// "h_e_l_l_o_ _w_o_r_l_d"
10.函数
10.1 创建函数
// 1.函数声明:会被前置
function add (a, b) {
a = +a;
b = +b;
if (isNaN(a) || isNaN(b)) {
return;
}
return a + b;
}
// 2.函数表达式
// function variable
var add = function (a, b) {
// do sth
};
// IEF(Immediately Executed Function) 匿名函数表达式
(function() {
// do sth
})();
// first-class function 把函数对象作为返回值
return function() {
// do sth
};
// NFE (Named Function Expression) 命名式函数表达式
var add = function foo (a, b) {
// do sth
};
10.2 命名函数表达式(NFE)
var func = function nfe() {};
alert(func === nfe); // IE6~8为false,IE9报错,nfe为undefined
// 递归调用
var func = function nfe() {/** do sth.**/ nfe();}
10.3 Function构造器
var func = new Function('a', 'b', 'console.log(a + b);');
func(1, 2); // 3
var func = Function('a', 'b', 'console.log(a + b);');
func(1, 2); // 3
// 案例1: localVal仍为局部变量
Function('var localVal = "local"; console.log(localVal);')();
console.log(typeof localVal);
// result: local, undefined
// 案例2: localVal不可访问,全局变量global可以访问
var globalVal = 'global';
(function() {
var localVal = 'local';
Function('console.log(typeof localVal, typeof globalVal);')();
})();
// result: undefined, string
10.4 this
10.4.1 全局this
console.log(this.document === document); // true
console.log(this === window); // true
this.a = 37;
console.log(window.a); // 37
10.4.2 一般函数的this
function f1(){
return this;
}
f1() === window; // true, global object
function f2(){
"use strict"; // see strict mode
return this;
}
f2() === undefined; // true
10.4.3 作为对象方法的函数的this
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // logs 37
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37
10.4.4 对象原型链上的this
var o = {f:function(){ return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
10.4.5 get/set方法与this
function modulus(){
return Math.sqrt(this.re * this.re + this.im * this.im);
}
var o = {
re: 1,
im: -1,
get phase(){
return Math.atan2(this.im, this.re);
}
};
Object.defineProperty(o, 'modulus', {
get: modulus, enumerable:true, configurable:true});
console.log(o.phase, o.modulus); // logs -0.78 1.4142
10.4.6 构造器中的this
function MyClass(){
this.a = 37;
}
var o = new MyClass();
console.log(o.a); // 37
function C2(){
this.a = 37;
return {a : 38};
}
o = new C2();
console.log(o.a); // 38
10.4.7 call/apply方法与this
function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // "[object Number]"
10.4.8 bind方法与this
function f(){
return this.a;
}
var g = f.bind({a : "test"});
console.log(g()); // test
var o = {a : 37, f : f, g : g};
console.log(o.f(), o.g()); // 37, test
10.5 函数属性 & arguments
10.5.1 arguments
function foo(x, y, z) {
arguments.length; // 2 实参个数
arguments[0]; // 1
arguments[0] = 10;
x; // change to 10;
arguments[2] = 100;
z; // still undefined !!!
arguments.callee === foo; // true
}
foo(1, 2);
foo.length; // 3 形参个数
foo.name; // "foo" 函数名
10.5.2 apply/call方法
function foo(x, y) {
'use strict';
console.log(x, y, this);
}
foo.apply(null); // undefined, undefined, null
foo.apply(undefined); // undefined, undefined, undefined
10.5.3 bind方法
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var getX = module.getX;
getX(); // 9
var boundGetX = getX.bind(module);
boundGetX(); // 81
10.5.4 bind与currying
function add(a, b, c) {
return a + b + c;
}
var func = add.bind(undefined, 100); // 定义a为100
func(1, 2); // 103
var func2 = func.bind(undefined, 200); // 定义b为200
func2(10); // 310
10.5.5 bind与new
function foo() {
this.b = 100;
return this.a;
}
var func = foo.bind({a:1});
func(); // 1
new func(); // {b : 100}
11.闭包
11.1 闭包的概念
闭包就是能够读取其他函数内部变量的函数。
// 1.取不到局部变量n
function f1(){
var n=999;
}
alert(n); // error
// 可以通过闭包获取局部变量n
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
11.2 闭包-常见错误之循环闭包
// addEventListener是一个回调函数,当你点击的时候才会动态去拿i的值,所以都是4
document.body.innerHTML = "<div id=div1>aaa</div>"
+ "<div id=div2>bbb</div><div id=div3>ccc</div>";
for (var i = 1; i < 4; i++) {
document.getElementById('div' + i).
addEventListener('click', function() {
alert(i); // all are 4!
});
}
// 绑定一个立即执行的闭包函数
document.body.innerHTML = "<div id=div1>aaa</div>"
+ "<div id=div2>bbb</div><div id=div3>ccc</div>";
for (var i = 1; i < 4; i++) {
!function(i) {
document.getElementById('div' + i).
addEventListener('click', function() {
alert(i); // 1, 2, 3
});
}(i);
}
11.3 闭包-封装
(function() {
var _userId = 23492;
var _typeId = 'item';
var export = {};
function converter(userId) {
return +userId;
}
export.getUserId = function() {
return converter(_userId);
}
export.getTypeId = function() {
return _typeId;
}
window.export = export;
}());
export.getUserId(); // 23492
export.getTypeId(); // item
export._userId; // undefined
export._typeId; // undefined
export.converter; // undefined
12.作用域
12.1 全局,函数,eval
var a = 10; // 全局作用域
(function() {
var b = 20; // 函数作用域
})();
console.log(a); // 10
console.log(b); // error, b in not defined
// javascript中没有块级作用域,这里定义的item还是全局作用域
for (var item in {a : 1, b : 2}) {
console.log(item);
}
console.log(item); // item still in scope
eval("var a = 1;"); // eval作用域
12.2 作用域链
function outer2() {
var local2 = 2;
function outer1() {
var local1 = 1;
// visit local1, local2 or global3
console.log(local1 + "," + local2 + "," + global3);
}
outer1();
}
var global3 = 3;
outer2();
// new Function()方式访问不到变量i
function outer() {
var i = 1;
var func = new Function("console.log(typeof i);");
func(); // undefined
}
outer();
12.3 利用函数作用域封装
// 通过()或者!来把函数声明变成函数表达式,里面的a,b变量对应也会变成局部变量
(function() {
// do sth here
var a, b;
})();
!function() {
// do sth here
var a, b;
}();
13. ES3(ECMAScript3)执行上下文
13.1 执行上下文(Execution Context)
console.log('EC0');
function funcEC1() {
console.log('EC1');
var funcEC2 = function() {
console.log('EC2');
var funcEC3 = function() {
console.log('EC3');
};
funcEC3();
}
funcEC2();
}
funcEC1();
// EC0 EC1 EC2 EC3
13.2 变量对象
变量对象(Variable Object, 缩写为VO)是一个抽象概念中的“对象”,它用于存储执行上下文中的:
1. 变量
2. 函数声明
3. 函数参数
activeExecutionContext = {
VO : {
data_var,
data_func_declaration,
data_func_arguments
}
};
GlobalContextVO (VO === this === global)
13.3 执行上下文和变量对象
var a = 10;
function test(x) {
var b = 20;
}
test(30);
// 对应关系如下:
// 全局上下文环境中有个a变量和test函数
VO(globalContext) = {
a : 10,
test : <ref to function>
};
// 函数上下文环境中有个变量b和参数a
VO(test functionContext) = {
x : 30,
b: 20
};
13.4 全局执行上下文(浏览器)
VO(globalContext) === [[global]];
[[global]] = {
Math : <...>,
String : <...>,
isNaN : function() {[Native Code]}
...
...
window : global // applied by browser(host)
};
String(10); //[[global]].String(10);
window.a = 10; // [[global]].window.a = 10
this.b = 20; // [[global]].b = 20;
GlobalContextVO (VO === this === global)
13.5 函数中的激活对象
VO(functionContext) === AO;
AO = {
arguments : <Arg0>
};
arguments = {
callee,
length,
properties-indexes
};
13.6 变量初始化阶段
VO按照如下顺序填充:
1.函数参数
(若未传⼊入,初始化该参数值为undefined)
2.函数声明
(若发生命名冲突,会覆盖)
3.变量声明
(初始化变量值为undefined,若发⽣生命名冲突,会忽略。)
function test(a, b) {
var c = 10;
function d() {}
var e = function _e() {};
(function x() {});
b = 20;
}
test(10);
// 对应关系如下:
AO(test) = {
a: 10,
b: undefined,
c: undefined,
d: <ref to func "d">
e: undefined
};
13.7 代码执行阶段
function test(a, b) {
var c = 10;
function d() {}
var e = function _e() {};
(function x() {});
b = 20;
}
test(10);
// 对应关系如下:
AO(test) = {
a: 10,
b: 20,
c: 10,
d: <reference to FunctionDeclaration "d">
e: function _e() {};
};
13.8 Demo
alert(x); // function
alert(a); // undefined
alert(b); // undefined
var x = 10;
alert(x); // 10
x = 20;
function x() {}
alert(x); // 20
if (true) {
var a = 1;
} else {
var b = true;
}
alert(a); // 1
alert(b); // undefined
14.OOP(面向对象编程) 特性: 继承 封装 多态 抽象
14.1 继承实例代码
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.hi = function(){
console.log("Hi,my name is " + this.name + ",I'm" + this.age + " years old now");
};
Person.prototype.LEGS_NUM = 2;
Person.prototype.ARMS_NUM = 2;
Person.prototype.walk = function(){
console.log(this.name + " is walking");
};
function Student(name,age,className){
Person.call(this,name,age);
this.className = className;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.hi = function(){
console.log("Hi,my name is " + this.name + ",I'm" +
this.age + " years old now,and from " +
this.className + "." );
};
Student.prototype.learn = function(subject){
console.log(this.name + " is learning" + subject + "at" +
this.className + ".");
}
// test
var mike = new Student("Mike",22,"Class 3,Grade 2");
mike.hi(); // Hi,my name is Mike,I'm22years old now,and fromClass 3,Grade 2.
mike.LEGS_NUM; // 2
mike.walk(); // Mikeis walking
mike.learn("math"); // Mikeis learningmathatClass 3,Grade 2.
14.2 prototype对象属性
Student.prototype.x = 101;
mike.x; // 101
// 可以看出对于已经实例化的对象,更改student的prototype属性并不会影响该实例所指向的proto原型
Student.prototype = {y:2};
mike.y; // undefined
mike.x; // 101
// 新创建一个实例则会影响
var newStu = new Student("test",3,"class 1");
newStu.x; // undefined
newStu.y; // 2
总结:
1.动态修改prototype的属性的时候,是会影响所有实例的。
2.动态修改整个prototype的话,是不会影响已经创建的实例,但会影响后续创建的实例。
14.3 实现继承的方式
function Person(){}
function Student(){}
// 第一种方法,错误,因为改变student的同时会把person的也改变了
Student.prototype = Person.prototype;
// 第二种方法,调用了Person的构造函数创建了一个实例
// 但是假如构造函数需要传参的话,最好不要使用这种方式
Student.prototype = new Person();
// 第三种方法,ES5之后才支持,使用Object.create()方法
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
// 但是没关系,我们可以自己模拟create方法
if(!Object.create){
Object.create = function(proto){
function F(){}
F.prototype = proto;
return new F;
};
}
14.4 模拟重载
// 因为JS是弱类型语法,所以对重载的支持需要自己模拟
function Person() {
var args = arguments;
if(typeof args[0] === 'object' && args[0]) {
if(args[0].name) {
this.name = args[0].name;
}
if(args[0].age) {
this.age = args[0].age;
}
} else {
if(args[0]) {
this.name = args[0];
}
if(args[1]) {
this.age = args[1];
}
}
}
Person.prototype.toString = function() {
return "name = " + this.name + ",age = " + this.age;
}
var mike = new Person("Mike",22);
mike.toString();
var mike2 = new Person({name: "mike2", age: 22});
mike2.toString();
14.5 链式调用(模拟jquery)
function ClassManager() {}
ClassManager.prototype.addClass = function(str){
console.log("Class:" + str + "added.");
return this;
};
var manager = new ClassManager();
manager.addClass("classA").addClass("classB").addClass("classC");
14.6 抽象类(自定义模拟)
function DetectorBase() {
// 不想直接被调用,可以采取抛出异常的方式
throw new Error("Abstract class can not be invoked directly!");
}
DetectorBase.detect = function(){console.log("Detection starting...");};
DetectorBase.stop = function(){console.log("Detector stopped.");};
DetectorBase.init = function(){throw new Error("Error");};
function LinkDetector(){}
LinkDetector.prototype = Object.create(Detector.prototype);
LinkDetector.prototype.constructor = LinkDetector;
14.7 实践--探测器
!function(global) {
function DetectorBase(configs) {
// 必须使用new创建
if(!this instanceof DetectorBase) {
throw new Error("Do not invoke without new.");
}
this.configs = configs;
this.analyze();
}
DetectorBase.prototype.detect = function() {
throw new Error("Not implemented");
};
DetectorBase.prototype.analyze = function() {
console.log("analyzing...");
this.data = "###data###";
}
function LinkDetector(links) {
if(!this instanceof LinkDetector) {
throw new Error("Do not invoke without new.");
}
this.links = links;
DetectorBase.apply(this,arguments);
}
function ContaninerDetector(containers) {
if(!this instanceof ContaninerDetector) {
throw new Error("Do not invoke without new.");
}
this.containers = containers;
DetectorBase.apply(this,arguments);
}
// inherit first 先继承
inherit(LinkDetector,DetectorBase);
inherit(ContaninerDetector,DetectorBase);
// expand later 后扩展
LinkDetector.prototype.detect = function() {
console.log("Loading data:" + this.data);
console.log("Link detection started.");
console.log("Scaning links:" + this.links);
};
ContaninerDetector.prototype.detect = function() {
console.log("Loading data:" + this.data);
console.log("Container detection started.");
console.log("Scaning links:" + this.containers);
}
// prevent from being altered
Object.freeze(DetectorBase);
Object.freeze(DetectorBase.prototype);
Object.freeze(LinkDetector);
Object.freeze(LinkDetector.prototype);
Object.freeze(ContaninerDetector);
Object.freeze(ContaninerDetector.prototype);
// export to global object
Object.defineProperties(global,{
LinkDetector: {value: LinkDetector},
ContaninerDetector: {value: ContaninerDetector},
DetectorBase: {value: DetectorBase}
});
function inherit(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
}
}(this);
// 容器探测器
var cd = new ContaninerDetector("#abc #def #ghi");
// 链接探测器
var ld = new LinkDetector("http://www.baidu.com http://www.taobao.com");
cd.detect();
ld.detect();
15.正则表达式
15.1 正则表达式两种写法
第一种://隔开
/\d\d\d/.test("123"); // true
/\d\d\d/.test("abc"); // false
第二种:使用RegExp构造器
new RegExp("Mike").test("Hi,Mike");
15.2 特殊符转义(使用\)
/\^abc/.test("^abc"); // true
15.3 分组
第一种:只是使用括号括起来,那么\1就表示分组的内容,即abc
/(abc)\1/.test("abcabc"); // true
第二种:使用(?:x)的形式,那么就没有\1表示分组内容的快捷方式
/(?:abc)(def)\1/.test("abcdefdef"); // true
15.4 三个flag(global,ignoreCase,multiline)
/abc/gim.test("ABC"); //true
RegExp("abc","mgi").test("ABC"); // true
15.5 RegExp对象属性
/abc/g.global // true
/abc/g.ignoreCase // false
/abc/g.multiline // false
/abc/g.source // "abc"
15.6 RegExp对象方法
/abc/.exec("abcdef"); // "abc",正则的一个匹配方法
/abc/.test("abcde"); // true
/abc/.toString(); // "/abc/"
var reg = /abc/;
reg.compile("def"); // 可以改变正则的属性
reg.test("def"); // true
15.7 String类型与正则相关的方法(search/replace/match/split)
"abcabcdef".search(/(abc)\1/); // 0
"aabbbbcc".replace(/b+?/,"1"); // aa1bbbcc
"aabbbbcc".match(/b+/); // ["bbbb"]
"aabbbbccbbaa".match(/b+/g); // ["bbbb","bb"]
"aabbbbccbbaa".split(/b+/); //["aa","cc","aa"]
JavaScript学习笔记
最新推荐文章于 2023-01-15 13:49:32 发布