for in
当我们遍历一个数组的时候,可以有length方法去获知数组的长度,进而设置循环上限去遍历,可是对象没有length方法,我们就只能利用for in方法去遍历:
obj={
work:student,
name = "xxx",
sex="male",
proe:123,
}
for (var x in obj){
console.log(x);
}
程序的结果会是依次输出work,name,sex,proe;当我们想要依次获取属性值的时候,最先想到的一定会是:
for (var x in obj){
console.log(obj.x);
}
但结果却会超出我们的的预期,他会输出四个undefined,为什么会这样呢?
我们需要知道的是obj.x------>obj[‘x’],这两个语法是相等的,当我们每次对象.属性时,程序就会帮我们做这样的隐式转换。所以在程序中,它会认为是我们在寻找obj对象当中的x属性,没有就会输出undefined,这是新手常常会犯的一个错误。我们只需要将代码改成如下:
for (var x in obj){
console.log(obj[x]);
}
这样,x就会作为一个变量去使用,而不会再被隐式的转化为字符串了。
这个方法用来判断自己所定义的所有属性/方法,返回值为布尔内型
对象.hasOwnProperty("属性值/方法")
只要是自己所定义的,他都会返回true,即使我们以这样的方式来定义:Object.prototype.abc=123;
把属性定义在他的顶级原型中,当我们判断时依旧会返回给我们true,但当我们想要判断顶级原型中的toString()方法,由于是系统自动定义,所以会返回true。
ABC in A
这个方法类似于上一个方法,他也用来判断某一属性或方法是否存在于对象,但不同的是,它的搜索范围在整个原型链当中,不管是不是我们自己定义的,只要存在,他就会返回true。
这个方法用来判断A的原型链上有没有B的原型。
A instanceof B;
我们就可以用这种方法来判断,对象和数组的区别,[ ] instanceof Array返回的是true,而{ } instanceof Array返回的就会是false。
callee方法是被定义在arguments对象身上的,用来判断函数的引用,当一些立即执行函数,需要使用递归时,发现它自身是没有函数名的,所以我们就会用到这个方法:
//递归计算100的阶乘
var test = (
function (n){
if (n === 1)
return;
else
return n * arguments.callee(n-1);
}(100))
返回当前调用的环境,主要是要区分它和callee方法的不同之处,一个返回当前环境,一个返回函数引用。
克隆我们也可以称之为复制,把一个对象完全的复制到另一个对象的身上,我们可以利用函数去遍历原始对象,然后用新对象一个一个的去接收原始对象的属性,若属性为原始内型,我们复制的只是表层的数据,但当属性为引用值时,我们复制过来的就将会是引用值得地址,当我们修改原始属性时,复制后对象的相应属性也会受到影响,所以我们要做进一步的优化克隆,编写以下函数来解决上述问题:
obj={
name:"xxx,
a:1,
b:[1,2,3,4],
c:{
c1:1,
c3:3,
c2:2
}
};
obj1={};
function Clone(target,origin){
var target = target || {};
var toStr = Object.prototype.toString();
var strRes = "[Object,Array]";
for (var proe in origin){
if(origin.hasOwnProperty(proe)){
if(typeof(origin[proe]) !== 'null' && typeof(origin[proe]) == 'Object'){
if(toStr.call(origin[proe] == strRes)){
target[proe] = [];
}
else{
target[proe] = {};
}
Clone(origin[proe],target[proe]);
}
else{
target[proe] = origin[proe];
}
}
}
return target;
}
obj和obj1分别代表被克隆和克隆的两个对象,Clone函数内部主要完成以下几个功能:
数组运行存在undefined,当我们**a = [1,2,3,,,4]**这样去定义数组的时候,他会将空缺值自动填补undefined,而不是报错,而且数组运行越界访问,同样会返回undefined,js当中对于数组的检查还是比较松的,一般情况不会报错,他一共有两种定义方式,一种是字面表达式,还有就是创建数组对象去定义,一般的话前者居多。
这里介绍几种关于数组的方法:
Array.prototype.push = function (target){
this[this.length] = target;
this,length++;
}
以上代码为Array原型中的push方法,底层基础有助于我们了解类数组中该如何改变属性值
pop方法
该方法可以在原数组去除最后一个元素。
unshift方法
该方法可以在原数组的最前面依次添加元素,添加个数不限。
shift方法
该方法可以在原数组去除最前面的一个元素。
reverse方法
该方法可以将原数组进行翻转显示。
splice方法
该方法用来切割数组,负数代表倒数元素。最多可以选择三个参数,
sort方法
该方法用于对于给数组排序,但是如果单纯的以数组名.sort()方法去调用它,结果可能和我们想象的还是有所差异,他会按字符编码去排,但是sort方法允许我们传一个函数去自定义按照我们的想法去排序,具体语法如下:
a = [1,4,-3,4,6,7,2,4,5];
a.sort(
//当返回值为正数的时候,保持位序不变
//当返回值为负数的时候,交换两数的位置
//当返回值为0的时候,保持位序不变
function (a,b) {
if(a < b){
return 1;
}
else{
return -1;
}
}
)
以上代码我们定义了一个正序的排序方法,由注释可知如何排序,可根据我们自己定义的返回值去判断,而sort的内部就相当于进行了冒泡排序的算法,一步一步的调用我们所传的这个函数去做判断,当然,代码有可以简化的部分,我们可以直接将函数体改为return a-b;
这样数组依旧可以进行正序排序,反之就会进行逆序排序。
Math.random()
方法每次回返回一个(0,1)范围里的数字,所以我们让它减去0.5,那么这个返回值就可能为负数,也有可能为正数,再将它作为sort参函数的返回值,就能够达到我们的需求。一个很像是数组的对象,如我们熟知的argument,它像是数组一样存储了我们的实参,但是数组所拥有的方法它全不具有,所以我们称它为类数组。
var obj = {
"0" : 'a',
"1" : 'b',
"2" : 'c',
"length" : 3,
"push" : Array.prototype.push
}
像这样我们主动给他加上数组所拥有的length属性以及push方法,把他变得更加像一个数组,然后我们就可以调用他的push方法了,在此之前,我们需要了解push方法的实质内涵,才能明白类数组如何去push属性,在前面我们已经提及过,他是要根据length属性的值来添加。他在”2”的后面加了一个”3”:’d’,并且lenngth也变成了四,这些都是一个对象不能具备的东西。
类数组必须有几个组成部分:
类数组最好包含的四个组成部分
28:
var obj = {
"2" : 'a',
"3" : 'b',
"length" : 2,
"push" : Array.prototype.push,
}
obj.push(obj);
this.length等于2,所以就把a换成c了吧,length等于3,第二次this.length等于2,把d换成d,length+1变成4。
var obj = {
"2" : 'c',
"3" : 'd',
"length" : 2,
"push" : Array.prototype.push,
}
主要思路是利用对象不可能存在重名属性,从数组依次读值,然后去对象中判断是否含有该属性,若没有则定义,若有则说明数组有重值,就可以过滤掉。
Array.prototype.unique=function () {
var len = this.length,obj = {},arr = [];
for(var i = 0;i < len;i++){
if(!obj[this[i]]){
obj[this[i]] = "xxx";//这里属性值可随意填写
arr.push(this[i]);
}
}
return arr;
}
当对象内未定义该方法,返回undefined,取非则为true,然后对它进行存储,属性值可以写除0外的任意值,因为当读取属性值返回0,取反,判断仍然为true,所以可能会存在存取误差。