js引用类型
js Object类型:
创建object实例的两种方法:
1.
var person = new Object();
2.对象字面量(见json和对象字面量的区别)
对象字面量常用与:
function displayInfo(args) { //对象字面量方法向函数传递可选参数 ,对于必须传递的参数使用命名参数
var output="";
if (typeof args.name== "string") {
output += "Name: " + args.name+ "\n";
}
if (typeof args.age == "number") {
output += "Age: " +args.age + "\n";
}
alert(output);
}
displayInfo({
name:"Nicholas",
age:29
});
displayInfo({
name: "Greg"
});
访问对象属性:
1.点表示法
alert(person.name);
2.方括号表示法
在用方括号表示法时,应该将要访问的属性以字符串形式放在方括号中:
alert(person["name"]);
这种方法的优点在于可以通过变量来访问属性:
var propertyName = "name";
alert(person[propertyName]);
而且如果属性名中有空格或者导致错误的字符,就不能用点表示法。
js Array类型:
数组的每一项可以保存任何类型的数据,即第一项和第二项可以不一样,第一项数值,第二项字符串。
创建数组的几种方法:
var colors = new Array(3); //创建一个包含三项的数组
var name = Array("Greg","laowang","xiaoming"); //new可以省略,包含三项,每项都是字符串。
数组字面量
var colors = ["red","green"];
重排序方法:
.reverse():
你可以使用
reverse
方法来翻转数组。
var myArray = [1, 2, 3];
myArray.reverse();
结果myArray 变成了 [3, 2, 1]
使用
reverse
来翻转
array
数组。并赋值给
newArray
.
.sort():
sort()方法按升序排列数组项,但是sort()方法会调用每个数组项的toString()转型方法,然后比较得到的字符串。
所以会有以下问题使sort()方法不能直接用来排序装着数字的数组:
var values = [0,1,5,10,15];
values.sort();
alert(values); // 0,1,10,15,5
在进行字符串比较的时候10是位于5的前面的。
sort()方法也因此可以接受一个比较函数作为参数:
语法
arr.sort([compareFunction])
参数
compareFunction是一个函数
可选。用来指定按某种顺序进行排列的函数。如果省略,元素按照转换为的字符串的诸个字符的Unicode位点进行排序。
如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。记 a 和 b 是两个将要被比较的元素:
- 如果 compareFunction(a, b) 小于 0 ,那么 a 会被排列到 b 之前;
- 如果 compareFunction(a, b) 等于 0 , a 和 b 的相对位置不变。
备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本);
- 如果 compareFunction(a, b) 大于 0 , b 会被排列到 a 之前。
- compareFunction(a, b) 必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
eg:
var arr=[2,5,1,3,2];
arr.sort(compare);
console.log(arr);
function compare(value1,value2) {
if(value1<value2) {
return -1;
} else if (value1>value2) {
return 1;
} else {
return 0;
}
}
.concat()和.slice():
concat()方法会创建当前数组的一个副本,然后将接收到的参数添加到副本的末尾,并返回这个副本,原数组不变。
slice()截取当前数组中的一个或多个项,组成一个新数组。接受的两个参数为截取的开始和结束为止,组成的新数组包含开始不包含结束位置的项。
如果只传入一个参数则从开始到原数组结尾。
.splice():
splice()方法可以用来删除、插入和替换。
其传入的前两个参数,第一个参数为开始修改数组的位置,第二个参数为删除原来数组元素的个数,其余的参数为插入到数组中的元素。
这个方法会改变原数组,返回值为被删除的元素组成的数组。
数组的迭代方法:
归并方法:
reduce()方法从数组的第一项开始,reduceRight()则从数组的最后一项开始,向前遍历到第一项。
value=[0,1,2,3,4,5].reduce(function(a,b,c,d){ //arr.reduce()
console.log(a,b,c,d);
return a+b;
},10);
console.log(value);//25
js RegExp 类型:
字面量模式和RegExp构造函数:
var pattern = /\[bc\]at/g;
var pattern2 = new RegExp("\\[bc\\]at","g"); //用构造函数时,参数必须是字符串,字符串中\前要用\转义,故和字面量模式有区别。
console.log(pattern+"\n"+pattern2);
RegExp实例方法:
exec():
var text = "something mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi;
var matches = pattern.exec(text);
//exec在没有匹配项时返回null,否则返回 包含第一个匹配项信息的 数组,数组包含两个额外的属性。
console.log(matches.index); //10
//index表示匹配项在字符串中的位置
console.log(matches.input); //something mom and dad and baby
//input表示应用正则表达式的字符串
console.log(matches[0]); //mom and dad and baby 匹配的整个字符串
console.log(matches[1]); //and dad and baby 第一个捕获组匹配的内容
console.log(matches[2]); //and baby
console.log(matches[3]); //undefined 数组长度只有3
在设置全局标志(g)时,同一个字符串多次调用exec()将会继续查找新匹配项,不设置时始终返回第一个匹配项的信息。
test():
var text="1213-81-81";
var pattern=/\d{4}-(\d{2})-\1/; // \1反向引用捕获组
if(pattern.test(text)){ // test()测试序列是否与模式匹配
console.log("The pattern was matched");
}
js 基本包装类型:
基本包装类型,也是一种引用类型。基本包装类型是对基本数据类型的封装,封装后即具有基本类型的功能,也有各自的特殊行为(方法)。
三个特殊的引用类型:Boolean,Number,String。
每当读取一个基本类型值的时候,后台会创建一个对应的基本包装类型的对象,从而我们可以调用一些方法来操作这些数据。
而自动创建的基本包装类型的对象只存在于一行读取模式访问的代码执行的瞬间,然后立即被销毁。
即在对基本类型用方法进行读取的时候,后台自动创建一个由基本类型得到的对象实例,再调用这个方法,调用完后销毁对象实例,基本类型值毫无影响。
基本包装类型也可以显式的被创建,但是不建议这么做,会容易分不清处理的是基本类型还是引用类型。
Boolean类型:
var falseObject = new Boolean(false);
var result = falseObject && true;
console.log(result); //true
var falseValue = false;
result = falseValue && true;
console.log(result); //false
在这个例子中,我们使用 false 值创建了一个 Boolean 对象。然后,将这个对象与基本类型值 true 构成了逻辑与表达式。在布尔运算中, false && true 等于 false 。可是,示例中的这行代码是对 falseObject 而不是对它的值( false )进行求值。前面讨论过,布尔表达式中的所有对象都会被转换为 true ,因此 falseObject 对象在布尔表达式中代表的是 true 。结果, true && true 当然就等于 true 了。
基本类型与引用类型的布尔值还有两个区别。首先, typeof 操作符对基本类型返回 “boolean” ,而对引用类型返回 “object” 。其次,由于 Boolean 对象是 Boolean 类型的实例,所以使用 instanceof 操作符测试 Boolean 对象会返回 true ,而测试基本类型的布尔值则返回 false 。例如:
alert(typeof falseObject); //object
alert(typeof falseValue); //boolean
alert(falseObject instanceof Boolean); //true
alert(falseValue instanceof Boolean); //false
理解基本类型的布尔值与 Boolean 对象之间的区别非常重要——当然,我们的建议是永远不要使用 Boolean 对象
Number类型:
Number类型 小数位数,进制,科学计数法,各种方法。
红宝书p121。
String类型:
var str = "这是汉字"; //字符串中包含的双字节字符也算一个字符
c(str.length); //4
1.字符方法:
var stringValue = "hello world";
c(stringValue.charAt(1)); //e
c(stringValue.charCodeAt(1)); //101
c(stringValue[1]); //e
2.字符串操作方法:
不影响原字符串,都是操作返回新字符串。
cancat(): (一般用”+“操作符)
c(stringValue.concat("!")); //hello world!
c(stringValue); //hello world 不影响原字符串
还有这些字符串操作方法 slice()、substring()、substr()。
3.字符串位置方法:
c(stringValue.indexOf("o")); //4
c(stringValue.lastIndexOf("o")); //7
c(stringValue.indexOf("o",6)); //7 从6开始向后搜索
c(stringValue.lastIndexOf("o",6)); //4 从6开始向前搜索
4.trim()
创建一个字符串的副本,删除字符串前后缀的所有空格。
5.字符串大小写转换方法:
,toLcaleUpperCase():
toLocaleUpperCase 方法:将字符转换为大写
stringVar.tolocaleUpperCase( )
必选的 stringVar 引用是一个 String 对象,值或文字。
.toUpperCase():
toUpperCase 方法
返回一个字符串,该字符串中的所有字母都被转化为大写字母。
strVariable.toUpperCase( )
"String Literal".toUpperCase( )
说明
toUpperCase 方法对非字母字符不会产生影响。
.toLocaleLowerCase():
toLocaleLowerCase 方法:将字符转换为小写
stringVar.tolocaleLowerCase( )
必选的 stringVar 引用是一个 String 对象,值或文字。
.toLowerCase():
toLowerCase()
会将调用该方法的字符串值转为小写形式,并返回。
eg:
str=str.toLowerCase();
返回一个字符串,该字符串中的字母被转换为小写字母。
strVariable.toLowerCase( )
"String Literal".toLowerCase( )
说明
toLowerCase 方法对非字母字符不会产生影响
6.字符串的模式匹配方法:
match():
类似于RegExp的exec()方法,match()方法只接受一个参数,要么是一个正则表达式,要么是一个regexp对象:
var text = "cat, bat, sat, fat";
var pattern = /.at/;
var matches=text.match(pattern);
c(matches.index); //0
c(matches[0]); //cat
c(matches[1]); //underfined
c(pattern.lastIndex); //0
c(matches.input); //cat, bat, sat, fat
注意:match()在模式设置全局标志g和不设置时返回的数组大不相同,设置g时返回所有匹配项而且没有index和input这两个属性。
search():
接受唯一参数和match()相同,从字符串开头向后查找,返回第一个匹配项的索引,没有找到返回-1;
replace():
为了简化替换子字符串的操作提供的方法,这个方法接受两个参数:
第一个参数可以是一个Regexp对象或者一个字符串(这个字符串不会被转换成正则表达式)
第二个参数可以是一个字符串或者一个函数
如果第一个参数是字符串,那么只会替换第一个自字符串,如果想替换所有子字符串,唯一的办法就是提供一个正则表达式,而且要指定全局标志(g):
var text = "cat, bat, sat, fat";
var pattern=/at/g;
var result1 = text.replace(pattern,"ond");
var result2 = text.replace(/at/g,"ond");
var result3 = text.replace("at","ond");
c(result1); //cond, bond, sond, fond
c(result2); //cond, bond, sond, fond
c(result3); //cond, bat, sat, fat
如果第二个参数是字符串,还可以使用一些特殊的字符序列:
$$ 直接量符号$。
$& 与 regexp 相匹配的子串。与Regexp.lastMatch的值相同。
$` 位于匹配子串左侧的文本。与Regexp.leftContext的值相同。
$' 位于匹配子串右侧的文本。与Regexp.rightContext的值相同。
$1、$2、...、$99 与 regexp 中的第 1 到第 99 个捕获组相匹配的文本。
var text = "cat, bat, sat, fat";
var result4 = text.replace(/at/,"$'");
var result5 = text.replace(/((a)t)/g,"$2");
c(result4); //c, bat, sat, fat, bat, sat, fat
c(result5); //ca, ba, sa, fa
如果第二个参数是函数,在只有一个匹配项时,会向这个函数传递三个参数,分别是:模式的匹配项、模式匹配项在字符串中的位置、原始字符串。
在正则表达式定义了多个捕获组的情况下,参数依次是:模式的匹配项、第一个捕获组的匹配项、第二个捕获组的匹配项······模式匹配项在字符串中的位置、原始字符串。
var text = "cat, bat, sat, fat";
function htmlEscape(text) {
return text.replace(/[<>"&]/g,function(match,pos,originalText){
switch(match) {
case "<":return "<";
case ">":return ">";
case "&":return "&";
case "\"":return """;
}
});
}c(htmlEscape("<p class=\"greeting\">Hello world!</p>")); //<p class="greeting">Hello world!</p>
split():
该方法基于指定的分隔符将一个字符串中分割成多个子字符串,并将结果存放到一个数组中。
分隔符可以是字符串,也可以是一个Regexp对象。
该方法的第二个参数为数字保证返回的字符串不超过这个大小。
var text = "cat, bat, sat, fat";
var result1=text.split(",",3);
var result2=text.split(/[^,]+/);
c(result1); //[ "cat", " bat", " sat" ]
c(result2); //[ "", ",", ",", ",", "" ]
js function类型:
函数是对象,函数名是指针,函数名实际上是一个指向函数对象的指针,不会与某个函数绑定,所以一个函数可能有多个名字。
定义函数的几种方法:
1.
function sum (num1,num2){ //结尾没有分号
return num1+num2;
}
2.
var sum = function(num1,num2){ //结尾有分号
return num1+num2;
};
3.
var sum = new Function("num1","num2","return num1+num2"); //性能不高不推荐 ,但可以直观理解函数是对象,函数名是指针
var num = sum(1,2);
console.log(num);
函数的参数和重载:
js函数本身不可以重载,如果理解函数名是指针的话,就不难理解为什么js没有重载。
重载是指:
函数的一种特殊情况,为方便使用,C++允许在同一范围中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用 同一个运算符完成不同的运算功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。
两个重载函数必须在下列一个或两个方面有所区别:
1、函数有不同参数。
2、函数有不同参数类型
而ECMAscript函数的参数在内部是用arguments数组表示的,ECMAscript命名参数只提供便利,但不是必须的。js解析器不会验证函数命名参数。
其实arguments本身是个对象,还具有一个叫callee的属性。
如果函数有参数,arguments数组里的值会和参数保持一致,但这两个值不是访问同一段内存,只是值会保持同步(非严格模式)。
eg:
function doAdd(num1,num2) {
if(arguments.length==1) {
alert(num1 + 10);
} else if (arguments.length==2) {
alert(arguments[0]+num2);
}
}
doAdd(2);
doAdd(2,3);
当js中定义了两个名字相同的函数时,后定义的函数会覆盖先定义的函数,
function addSomeNumber(num) { //js没有重载
return num + 100;
}
var result=addSomeNumber(100);
alert(result);//300
function addSomeNumber(num) {
return num + 200;
}
var result=addSomeNumber(100);
alert(result);//300
函数声明和函数表达式的区别:
函数声明可以提升,函数表达式定义法虽然也有提升但是提升的是变量,变量中不保存有对函数的引用,会产生错误。
console.log(sum(1,2)); //函数声明可以提升
function sum (num1,num2){
return num1+num2;
}
console.log(sum(1,2)); //函数声明可以提升,而函数表达式这么写会引起错误
var sum=function(num1,num2){ //函数表达式赋值到变量作为函数名
return num1+num2;
};
作为值的函数:
函数作为参数传递给另一个函数:
function callSomeFunction(SomeFunction,someArgument) {
return SomeFunction(someArgument);
}
function add10(num) {
return num + 10;
}
var result = callSomeFunction(add10,2);
console.log(result);
函数作为结果返回:
createComparisonFunction接收一个属性名,根据这个属性名创建一个函数并返回。
function createComparisonFunction(propertyName) { //函数可以返回一个函数
return function(object1,object2){
var value1=object1[propertyName];
var value2=object2[propertyName];
if(value1<value2){
return -1;
} else if (value1>value2){
return 1;
} else {
return 0;
}
};
}
var data=[{name:"Zachary",age:28},{name:"Nicholas",age:29}];
console.log(data.sort(createComparisonFunction("name")));
console.log(data[0]);
console.log(data.sort(createComparisonFunction("age")));
console.log(data[0]);
函数内部的两个特殊对象arguments和this:
arguments具有一个叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数:
function factorial(num){ //阶乘函数递归算法利用callee属性取消函数名和函数的耦合性
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
console.log(factorial(6));
this指的是函数据以执行的环境对象:
window.color = "red";
var o = {color:"blue"};
function sayColor(){
console.log(this.color);
}
sayColor(); //red
o.sayColor=sayColor;
o.sayColor(); //blue
函数的属性和方法:
每个函数都含有两个属性:
length:
函数的length属性是指函数希望接受的命名参数的个数:
function sayName(name) { //函数的length属性
console.log(name);
}
function sum (num1,num2) {
return num1 + num2;
}
function sayHi(){
console.log("hi");
}
console.log(sayName.length); //1
console.log(sum.length); //2
console.log(sayHi.length); //0
prototype:
引用类型的prototype属性是保存它们所有实例方法的真正所在。
另一个函数对象的属性:
caller属性中保存着调用当前函数的函数的引用。
每个函数都包含两个非继承来的方法:
apply()和call()这两个方法的用途都是在特定的作用域中调用函数,可以扩充函数赖以运行的作用域。
eg:
window.color="red";
var o={color:"blue"};
function sayColor(){
console.log((this.color));
}
sayColor(); //red
sayColor.call(this); //red
sayColor.call(window); //red
sayColor.call(o); //blue
它们都会接受第一个参数作为函数体内this的值,即相当于这个函数在this的环境对象下运行。
区别在于apply()接受两个参数,第二个参数可以是arguments对象,也可以是Array实例。
而call()接收参数必须逐一列出来。
apply():
function sum (num1,num2) { //函数的apply()方法传递参数的两种方法
return num1+num2;
}
function callSum1(num1,num2){
return sum.apply(this,arguments);
}
function callSum2(num1,num2) {
console.log(this); //window
return sum.apply(this,[num1,num2]);
}
console.log(callSum1(10,10)); //20
console.log(callSum2(10,10)); //20
call():
function sum(num1,num2) { //函数的call()方法传递参数需要逐一列出
return num1+num2;
}
function callSum(num1,num2) {
return sum.call(this,num1,num2);
}
console.log(callSum(10,10)); //20
console.log(this); //window
函数还有一个bind()方法:
这个方法创建一个函数实例,其this值会被绑定为传给bind()的参数
window.color = "red";
var o = {color:"blue"};
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
sayColor();
objectSayColor();