文章目录
一、原型对象
例子:
创建一个Person构造函数,在Person构造函数中,为每一个对象都添加了一个sayName方法。
1.1 原始方法
在构造函数内部创建,也就是构造函数每执行一次就会创建一个新的sayName方法。
弊端:
这样就导致了构造函数执行一次就会创建一个新的方法
,执行10000次就会创建10000个新的方法,而10000个方法都是一模一样,这是完全没有必要。
改进:
可以使所有的对象共享同一个方法。
1.2 改进方法
弊端:
将函数定义在全局作用域,污染了全局作用域的命名空间;而且定义在全局作用域中也很不安全。
改进:
利用原型对象。
1.3 原型对象
- 我们所创建的每一个函数,解析器都会向函数中添加一个
属性prototype
prototype属性指向的是一个对象,这个对象我们称为原型对象
。
- 当
函数作为构造函数使用
,它所创建的对象中都会有一个隐含的属性执行该原型对象;
这个隐含的属性可以通过对象.__proto__
来访问。 - 原型对象就相当于一个公共的区域,凡是通过同一个构造函数创建的对象他们通常都可以访问到相同的原型对象。
- 我们可以
将对象中共有的属性和方法统一添加到原型对象中
,这样我们只需要添加一次,就可以使所有的对象都可以使用。 - 当我们使用一个对象的属性或方法时,会
先在自身中寻找
,
自身中如果有,则直接使用,
如果没有则去原型对象中寻找,如果原型对象中有,则使用,
如果没有则去原型的原型中寻找,直到找到Object对象的原型,
Object对象的原型没有原型
,如果在Object原型中依然没有找到,则返回undefined
-
使用
in
检查对象中是否含有某个属性时,如果对象中没有但是原型中有
,也会返回true
。
-
hasOwnProperty():
这个方法可以用来检查对象自身中是否含有某个属性。
语法:对象.hasOwnProperty("属性名")
二、垃圾回收(GC)
- 程序运行过程中也会产生垃圾,这些垃圾积攒过多以后,会导致程序运行的速度过慢
- 当一个对象没有任何的变量或属性对它进行引用,此时我们将永远无法操作该对象,此时这种对象就是一个垃圾,这种对象过多会占用大量的内存空间,导致程序运行变慢,所以这种垃圾必须进行清理。
在JS中拥有自动的垃圾回收机制
,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收的操作我们需要做的只是要将不再使用的对象设置null即可
var obj = new Object();
//对对象进行各种操作。。。。
obj = null;
三、数组
3.1 数组简介
- 数组也是一个对象,是一个用来存储数据的对象,和Object类似,但是它的存储效率比普通对象要高
- 数组中保存的内容我们称为元素
- 数组使用索引(index)来操作元素
- 索引指由0开始的整数
- 数组中的元素可以是任意的数据类型
arr = ["hello",1,true,null,undefined];
//也可以是对象
arr = [{name:"孙悟空"},{name:"沙和尚"},{name:"猪八戒"}];
//也可以是一个函数
arr = [function(){alert(1)},function(){alert(2)}];
- 数组的操作:
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获取到的是数组的最大索引+1
- 对于连续的数组,length获取到的就是数组中元素的个数
5. 修改数组的长度
- 修改长度:数组.length = 新长度
- 如果修改后的length大于原长度,则多出的部分会空出来
- 如果修改后的length小于原长度,则原数组中多出的元素会被删除
6. 向数组的最后添加元素
- 数组[数组.length] = 值;
3.2 数组的几个方法
push()
用来向数组的末尾添加一个或多个元素,并返回数组新的长度
语法: 数组.push(元素1,元素2,元素N)
pop()
用来删除数组的最后一个元素,并返回被删除的元素
unshift()
向数组的前边添加一个或多个元素,并返回数组的新的长度
shift()
删除数组的前边的一个元素,并返回被删除的元素
示例:
<script>
//创建一个数组
var arr = ["孙悟空", "猪八戒", "沙和尚"];
/*
* push()
*/
var result = arr.push("唐僧", "蜘蛛精", "白骨精", "玉兔精");
console.log("result = " + result);
/*
* pop()
*/
result = arr.pop();
console.log("result = " + result);
/*
* unshift()
*/
arr.unshift("牛魔王", "二郎神");
console.log(arr);
/*
* shift()
*/
result = arr.shift();
console.log("result = " + result);
</script>
slice()
可以从一个数组中截取指定的元素
该方法不会影响原数组
,而是将截取到的内容封装为一个新的数组并返回
参数:
1.截取开始位置的索引(包括开始位置)
2.截取结束位置的索引(不包括结束位置)
注:
第二个参数可以省略不写,如果不写则一直截取到最后
参数可以传递一个负值,如果是负值,则从后往前数
splice()
可以用来删除数组中指定元素,并使用新的元素替换
该方法会改变原始数组
,会将删除的元素封装到新数组中返回
参数:
1.删除开始位置的索引
2.删除的个数
3.三个以后,都是替换的元素,这些元素将会插入到开始位置索引的前边
参数的不同数量起不同的效果:
删除——可以删除任意数量的项,只需要指定2个参数:要删除的第一项的位置和要删除项的项数。
splice(0,2) //会删除数组中的前两项
插入——可以向指定位置插入任意数量的项,只需要提供3个参数:插入起始位置、0(要删除的项数)和要插入的项。 如果要插入多个项,可以再传入第四、第五,一直任意多个项。
splice(2,0,”red”,”green”) //会从位置2开始插入字符串“red”和”green”
替换——可以向指定位置插入任意数量的项且
同时删除任意数量的项,只需要指定3个指定参数:起始位置、要删除的项数和要插入的任意数量项。 插入的项数是不必与删除的项数相等
。
练习:去掉数组中重复的元素
<script type="text/javascript">
//创建一个数组
var arr = [1,2,3,2,2,1,3,4,2,5];
//去除数组中重复的数字
//获取数组中的每一个元素
for(var i=0 ; i<arr.length ; i++){
//获取当前元素后的所有元素
for(var j=i+1 ; j<arr.length ; j++){
//判断两个元素的值是否相等
if(arr[i] == arr[j]){
//如果相等则证明出现了重复的元素,则删除j对应的元素
arr.splice(j,1);
//当删除了当前j所在的元素以后,后边的元素会自动补位
//此时将不会再比较这个补位元素,我们需要再比较一次j所在位置的元素
//使j自减
j--;
}
}
}
console.log(arr);
</script>
concat()
可以连接两个或多个数组,它不会影响原数组
,而是新数组作为返回值返回
reverse()
可以用来反转一个数组,它会对原数组产生影响
join()
可以将一个数组转换为一个字符串
参数:
需要一个字符串作为参数,这个字符串将会作为连接符来连接数组中的元素
如果不指定连接符则默认使用,
sort()
- 可以对一个数组中的内容进行排序,
默认是按照Unicode编码进行排序
。它会影响原数组。
- 可以自己指定排序的规则,需要一个
回调函数
作为参数:
arr = [5,4,2,1,3,6,8,7];
arr.sort(function(a,b){
//升序排列
//return a-b;
//降序排列
return b-a;
}
原因解释:
- 即使对于纯数字的数组,使用sort()排序时,也会按照Unicode编码来排序,
所以对数字进排序时,可能会得到错误的结果。
- 我们可以自己来指定排序的规则,我们可以在sort()添加一个回调函数,来指定排序规则。
- 回调函数中需要定义两个形参, 浏览器将会分别使用数组中的元素作为实参去调用回调函数,使用哪个元素调用不确定,但是肯定的是在数组中a一定在b前边
- 浏览器会根据回调函数的返回值来决定元素的顺序,
如果返回一个大于0的值,则元素会交换位置
如果返回一个小于0的值,则元素位置不变
如果返回一个0,则认为两个元素相等,也不交换位置 - 如果需要升序排列,则返回 a-b
如果需要降序排列,则返回b-a
注:
一个函数A,作为另一个函数B的参数,那么函数A就被称为回调函数
。
3.3 数组的遍历
Way1: 一般情况我们都是使用for循环
来遍历数组:
for(var i=0 ; i<数组.length ; i++){
//数组[i]
}
Way2: 使用forEach()方法
来遍历数组 (不兼容IE8及以下浏览器)
//value:正在遍历的元素 index:正在遍历元素的索引 obj:被遍历对象
数组.forEach(function(value , index , obj){
});
forEach()方法需要一个回调函数
作为参数,数组中有几个元素,回调函数就会被调用几次,每次调用时,都会将遍历到的信息以实参的形式传递进来,我们可以定义形参来获取这些信息。
示例:
<script>
//创建一个数组
var arr = ["孙悟空", "猪八戒", "沙和尚", "唐僧", "白骨精"];
arr.forEach(function (value, index, obj) {
console.log(value);
});
</script>
四、函数的call()和apply()方法
call()
apply()
- 这两个方法都是函数对象的方法,需要通过函数对象来调用
- 在调用call()和apply()可以将一个对象指定为第一个参数,
此时这个对象将会成为函数执行时的this
<script type="text/javascript">
function fun() {
alert(this.name);
}
var obj = {
name: "obj",
sayName: function () {
document.write(this.name);
}
};
var obj2 = {
name: "obj2"
};
//this是obj对象
fun.call(obj); //fun();调用时this是window
//将sayName方法中的this改为了obj2对象
obj.sayName.apply(obj2);
</script>
- call()方法可以将实参放在对象之后依次传递,apply()方法需要将实参封装到一个数组中统一传递
<script type="text/javascript">
function fun(a,b) {
console.log("a = "+a);
console.log("b = "+b);
}
var obj = {
name: "obj",
sayName:function(){
alert(this.name);
}
};
//fun.call(obj,2,3);
fun.apply(obj,[2,3]);
</script>
五、函数的两个隐含参数
arguments
- 在调用函数时,浏览器每次都会传递进两个隐含的参数:
1.函数的上下文对象this
2.封装实参的对象arguments
- arguments是一个
类数组对象
(不是数组),它也可以通过索引来操作数据,也可以获取长度 - 在调用函数时,我们所传递的实参都会在arguments中保存
- arguments.length可以用来获取实参的长度
- 我们即使不定义形参,也可以通过arguments来使用实参,只不过比较麻烦
- arguments中有一个属性callee表示当前执行的函数对象
this
- this是函数的上下文对象,根据函数的调用方式不同会指向不同的对象
- 以函数的形式调用时,this是window
- 以方法的形式调用时,this是调用方法的对象
- 以构造函数的形式调用时,this是新建的那个对象
- 使用call和apply调用时,this是指定的那个对象
- 在全局作用域中this代表window