一、构造函数
构造函数是专门用来创建对象的函数,一个构造函数也可以称为一个类。
通过一个构造函数创建的对象,我们称该对象为这个构造函数的一个实例。
通过同一个构造函数创建的对象,我们称为一类对象。
通过一个构造函数创建的对象,我们称该对象为这个构造函数的一个实例。
通过同一个构造函数创建的对象,我们称为一类对象。
构造函数就是一个普通的函数,只是他的调用方式不同:
1、如果直接调用,它就是一个普通函数。
2、如果使用new来调用,则它就是一个构造函数。
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function(){
alert(this.name);
};
}
var per1 = new Person("monicx",18,"男");
var per2 = new Person("benjin",16,"女");
var per3 = new Person("gaogge",38,"男");
构造函数的执行流程:
1.创建一个新的对象
2.将新的对象作为函数的上下文对象(this)
3.执行函数中的代码
4.将新建的对象返回
用“instanceof” 来检查一个对象是否是一个类的实例:
console.log(per1 instanceof Person)
语法:对象 instanceof 构造函数
如果该对象时构造函数的实例,则返回true,否则返回false
Object是所有对象的祖先,所以任何对象和Object做instanceof都会返回true
二、词法分析
JavaScript中在调用函数的那一瞬间,会先进行词法分析。
词法分析的过程:
当函数调用的前一瞬间,会先形成一个激活对象:Avtive Object(AO),并会分析以下3个方面:
1:函数参数,如果有,则将此参数赋值给AO,且值为undefined。如果没有,则不做任何操作。
2:函数局部变量,如果AO上有同名的值,则不做任何操作。如果没有,则将此变量赋值给AO,并且值为undefined。
3:函数声明,如果AO上有,则会将AO上的对象覆盖。如果没有,则不做任何操作。
例子一:
var age = 18;
function foo(){
console.log(age);
var age = 22;
console.log(age);
}
foo(); // 问:执行foo()之后的结果是?
例子二:
var age = 18;
function foo(){
console.log(age);
var age = 22;
console.log(age);
function age(){
console.log("呵呵");
}
console.log(age);
}
foo(); // 执行后的结果是?
词法分析过程:
1、分析参数,有一个参数,形成一个 AO.age=undefine;
2、分析变量声明,有一个 var age, 发现 AO 上面已经有一个 AO.age,因此不做任何处理
3、分析函数声明,有一个 function age(){...} 声明, 则把原有的 age 覆盖成 AO.age=function(){...};
最终,AO上的属性只有一个age,并且值为一个函数声明
执行过程:
注意:执行过程中所有的值都是从AO对象上去寻找
1、执行第一个 console.log(age) 时,此时的 AO.age 是一个函数,所以第一个输出的一个函数
2、这句 var age=22; 是对 AO.age 的属性赋值, 此时AO.age=22 ,所以在第二个输出的是 2
3、同理第三个输出的还是22, 因为中间再没有改变age值的语句了
三、原型(prototype)
创建一个函数以后,解析器都会默认在函数中添加一个数prototype属性指向的是一个对象,这个对象我们称为原型对象。
当函数作为构造函数使用,它所创建的对象中都会有一个隐含的属性执行该原型对象。
这个隐含的属性可以通过对象.__proto__来访问。
原型对象就相当于一个公共的区域,凡是通过同一个构造函数创建的对象他们通常都可以访问到相同的原型对象。我们可以将对象中共有的属性和方法统一添加到原型对象中,这样我们只需要添加一次,就可以使所有的对象都可以使用。
当函数作为构造函数使用,它所创建的对象中都会有一个隐含的属性执行该原型对象。
这个隐含的属性可以通过对象.__proto__来访问。
原型对象就相当于一个公共的区域,凡是通过同一个构造函数创建的对象他们通常都可以访问到相同的原型对象。我们可以将对象中共有的属性和方法统一添加到原型对象中,这样我们只需要添加一次,就可以使所有的对象都可以使用。
function MyClass(){
}
//向MyClass的原型中添加属性a
MyClass.prototype.a = 123;
//向MyClass的原型中添加一个方法
MyClass.prototype.sayHello = function(){
alert("hello");
};
var mc1 = new MyClass();
var mc2 = new MyClass();
//console.log(MyClass.prototype);
//console.log(mc2.__proto__ == MyClass.prototype);
//向mc中添加a属性
mc1.a = "我是mc1中的a";
//console.log(mc2.a);
mc1.sayHello();
原型对象也是对象,所以它也有原型,当我们去访问对象的一个属性或调用对象的一个方法时,它会先自身中寻找:
如果在自身中找到了,则直接使用。
如果没有找到,则去原型对象中寻找,如果找到了则使用,
如果没有找到,则去原型的原型中寻找,依此类推。直到找到Object的原型为止,Object的原型的原型为null,
如果依然没有找到则返回undefined。
hasOwnProperty()
这个方法可以用来检查对象自身中是否含有某个属性
语法:对象.hasOwnProperty("属性名")
四、数组(Array)
数组也是一个对象,是一个用来存储数据的对象,和Object类似,
但是它的存储效率比普通对象要高,
数组中保存的内容我们称为元素 ,
数组使用索引(index)来操作元素,索引指由0开始的整数。
数组的操作:
1、创建数组
var arr = new Array();
var arr = [];
2、向数组中添加元素
语法;
数组对象[索引] = 值;
arr[0] = 123;
arr[1] = "hello";
3、创建数组时直接添加元素
语法:
var arr = [元素1,元素2....元素N];
例子:
var arr = [123,"hello",true,null];
4、获取和修改数组的长度
使用length属性来操作数组的长度
获取长度:
数组.length
length获取到的是数组的最大索引+1
对于连续的数组,length获取到的就是数组中元素的个数
修改数组的长度
数组.length = 新长度
如果修改后的length大于原长度,则多出的部分会空出来
如果修改后的length小于原长度,则原数组中多出的元素会被删除
向数组的最后添加元素
数组[数组.length] = 值;
数组的方法
1、push()
用来向数组的末尾添加一个或多个元素,并返回数组新的长度
语法:数组.push(元素1,元素2,元素N)
2、pop()
用来删除数组的最后一个元素,并返回被删除的元素
3、unshift()
向数组的前边添加一个或多个元素,并返回数组的新的长度
4、shift()
删除数组的前边的一个元素,并返回被删除的元素
5、slice()
可以从一个数组中截取指定的元素
该方法不会影响原数组,而是将截取到的内容封装为一个新的数组并返回
参数:
1.截取开始位置的索引(包括开始位置)
2.截取结束位置的索引(不包括结束位置)
第二个参数可以省略不写,如果不写则一直截取到最后
参数可以传递一个负值,如果是负值,则从后往前数
6、splice()
可以用来删除数组中指定元素,并使用新的元素替换
该方法会将删除的元素封装到新数组中返回
参数:
1.删除开始位置的索引
2.删除的个数
3.三个以后,都是替换的元素,这些元素将会插入到开始位置索引的前边
7、reverse()
可以用来反转一个数组,它会对原数组产生影响
8、concat()
可以连接两个或多个数组,它不会影响原数组,而是新数组作为返回值返回
9、join()
可以将一个数组转换为一个字符串
参数:
需要一个字符串作为参数,这个字符串将会作为连接符来连接数组中的元素
如果不指定连接符则默认使用,
10、sort()
可以对一个数组中的内容进行排序,默认是按照Unicode编码进行排序
调用以后,会直接修改原数组。
可以自己指定排序的规则,需要一个回调函数作为参数:
function(a,b){
//升序排列
//return a-b;
//降序排列
return b-a;
}
sort()方法详解:
/*
* 即使对于纯数字的数组,使用sort()排序时,也会按照Unicode编码来排序,
* 所以对数字进排序时,可能会得到错误的结果。
*
* 我们可以自己来指定排序的规则
* 我们可以在sort()添加一个回调函数,来指定排序规则,
* 回调函数中需要定义两个形参,
* 浏览器将会分别使用数组中的元素作为实参去调用回调函数
* 使用哪个元素调用不确定,但是肯定的是在数组中a一定在b前边
* - 浏览器会根据回调函数的返回值来决定元素的顺序,
* 如果返回一个大于0的值,则元素会交换位置
* 如果返回一个小于0的值,则元素位置不变
* 如果返回一个0,则认为两个元素相等,也不交换位置
*
* - 如果需要升序排列,则返回 a-b
* 如果需要降序排列,则返回b-a
*/
arr = [5,4,2,1,3,6,8,7];
arr.sort(function(a,b){
//前边的大
/*if(a > b){
return -1;
}else if(a < b){
return 1;
}else{
return 0;
}*/
//升序排列
//return a - b;
//降序排列
return b - a;
});
console.log(arr);
遍历数组
一般情况我们都是使用for循环来遍历数组:
var arr = ["monicx1","monicx2","monicx3","monicx4","monicx5"];
for(var i=0 ; i<arr.length ; i++){
console.log(arr[i]);
}
使用forEach()方法来遍历数组(不兼容IE8)
var arr = ["monicx1","monicx2","monicx3","monicx4","monicx5"];
arr.forEach(function(value , index , obj){
console.log(value);
});
forEach()方法需要一个回调函数作为参数,
数组中有几个元素,回调函数就会被调用几次,
每次调用时,都会将遍历到的信息以实参的形式传递进来,
我们可以定义形参来获取这些信息。
value:正在遍历的元素
index:正在遍历元素的索引
obj:被遍历对象