JavaScript 秘密花园

来源:互联网 发布:大都会博物馆 知乎 编辑:程序博客网 时间:2024/05/01 11:12

参考 Javascript密码花园 http://www.jb51.net/onlineread/JavaScript-Garden-CN/

对象 {}

null 和undefined 不是对象,其他的都是对象。需要注意的是数字直接量,因为javascript数字直接量采用浮点型

所以类似 2.tostring() 会出错, 而2..toString() 则是正常的(ECMAScript3,暂不知道5有没有针对这个问题做处理),但是可以采用(2).toString()解决这个问题

对象的创建

有以下三种形式:
1.var foo = Object.create(Object.prototype);     Object.create(null).toString() 会报错,因为创建了一个空对象。2.var foo = {};3.var foo = new Object();

属性的查询与设置

有两种方式可以用来访问对象的属性,(.)点操作符和( [ ] )中括号操作符。
var foo = {name:Jocelyn};foo.name; //Jocelynfoo['name'] ; // Jocelyn

两种语言是等价的但是数组运算符可以用于动态设置属性和属性名不是有效的变量名的情况(ECMAScript3点操作符后不允许是保留字,ECMAScript5才对此放宽了限制),看一个例子
var address = “”;for(var i = 0; i < 4; i++) {     address += customer[‘address' + i];}
此处就可以配合其他变量来动态的设置值和取值了。

查询不存在的属性不会报错,.查询属性的对象不存在的情况下会报错
避免错误的方法 
var len = foo && foo.name && foo.name.length  //利用&&运算符的短路属性

设置属性报错的情况有如下几种:
     1.给只读属性赋值
     2.o是P中继承来的属性,不能通过设置自身同名属性去覆盖只读属性
     3.对象为不可扩展

对象继承

对象是基于原型链的继承 ,只在属性查询的时候会遍历原型链找属性,而在设置对象属性的时候只影响自身的属性,
如果自身存在这个属性则覆盖,不存在则创建(此处不考虑只读属性)。

删除属性

删除属性是使用delete操作符,设置属性为undefined或null的并不是真正的删除属性只是移除了属性与值的关联
delete不能删除通过var定义的内容。

枚举属性

看下面的例子
/**把p中的所有可枚举类型复制到o 并返回o如果o和p包含同名属性,取p的属性这个函数并不处理setter和getter以及复制属性**/function extend(o,p) {for(prop in p) {o[prop] = p[prop];}return o;}/**把p中的所有可枚举类型复制到o 并返回o如果o和p包含同名属性,o中属性不受影响这个函数并不处理setter和getter以及复制属性**/function merge(o,p) {for(prop in p) {if(o.hasOwnProperty[prop]) continue;o[prop] = p[prop];}return o;}/**如果o中得属性在p中没有同名属性,则从o中删除这个属性,并返回o**/function restrict(o,p) {for(prop in o) {//遍历o中所有属性if(!(prop in p)) delete o[prop];//如果 p中不存在,则删除之}return o;}/**如果o中的属性在p中存在同名属性,则从o中删除这个属性,并返回o**/function subtract(o,p) {for(prop in p) {delete o[prop];}return o;}/**返回一个新对象,这个对象同时拥有o的属性和p的属性如果o和p中有重名属性,取p中得属性值**/function union(o,p) {return extend(extebd({},o),p);}/**返回一个新对象,这个对象同时拥有o的属性和p的属性很像求o,p的交集,但p中得属性值会被忽略**/function intersection(o,p) {return restrict(extend({},o),p);}/**返回一个数组,这个数组包含的事o中可枚举的自有属性的名字**/function keys(o) {if(typeof o !== "object") throw TypeError();//参数必须似乎对象var result=[];//定义返回数组for(prop in o) {//遍历对象if(o.hasOwnProperty(prop)) {//判断是否自有属性result.push(prop);}}return result;}


加上属性特征的extend()方法

/**给Object.prototype添加一个不可枚举的属性 extend() 方法这个方法继承自调用它的对象,将作为参数传入的对象的属性一一复制除了值之外,也复制属性的所有特性,除非在目标对象中存在同名属性参数对象的所有自有属性(包括不可枚举的属性)也会被一一复制**/Object.defineProperty(Object.prototype添加一个不可枚举的属性,'extend',{writable : true,enumerable : false,configurable :true,value : function(o) {var names = Object.getOwnPropertyNames(o); //得到所有自有属性,包括不可枚举类型for( var i = 0; i < names.length; i++) {if(names[i] in this) continue; //获取o中得属性描述符var desc = Object.getOwnPropertyDescriptor(o,names[i]);//用它给this创建一个属性Object.defineProperty(this,names[i],desc);}}});


数组

     数组是值的有序集合
    

创建数组

<span style="white-space:pre"></span>var empty = [];    <span style="white-space:pre"></span>var misc = [1.1, ‘true’,];    <span style="white-space:pre"></span>var a = new Array();    <span style="white-space:pre"></span>var a = new Array(10); //(此种情况很可能出现稀疏数组)

推荐使用[]的方式创建数组 ,new Array在创建混合数组时的可读性较低。

数组元素的读写

数组元素的读写都是通过[index]的形式。需要注意的是,如果index为正整数且在数组长度内会采用索引的形式来访问属性,但是其他情况则采用属性名的形式访问数字,所以不会有“越界”一说。

稀疏数组与数组长度

      之前说过一种情况可能出现稀疏数组,通过delete操作也可能会产生稀疏数组。稀疏数组的length > 所有元素的索引值,而稠密数组的length为最大索引值加一。
     数组会自动维护length属性,这是数组最大的特色之一,设置length属性小于当前的length长度会导致数组中所以大于等于length的元素被删除。但设置新的length大于原有length仅仅是增加一段数组空间。

数组元素的添加与删除

     push() 在数组尾添加一个或多个元素
     unshift() 在数组首部添加一个元素 ,但需要注意的是一次性插入多个的顺序问题
     pop()删除数组尾部元素并返回删除元素
     detele() 注意,此方法不会修改数组的长度只会使其删除位置的值变成undefined
     splice() 是一个通用的插入删除替换的方法,会在后续详细说明

数组遍历

      使用for循环遍历 比采用for in循环遍历具有更多的优势,(小优化,数组的长度只应遍历一次而不是多次)
for in循环可能导致遍历的顺序不是按照数值的大小顺序而收属性影响采用创建顺序来遍历。所以尽量不要用for in循环而采用普通for循环。另外数组还提供一种forEach()方法;

数组方法

     join(sep) 将数组中所有元素转换成字符串并连接在一起;可指定一个参数作为分隔符。
     reverse(f) 将数组元素颠倒顺序并返回逆序的数组,不产生新的数组,只在原有的数组重新排序。
     sort(f) 跟reverse方法类似,只是返回顺序的数组。undefined元素会排在尾端。可自定义比较规则
     concat(ele) 创建并返回一个新的数组。若参数是数组则只连接数组元素并非数组本身。
     slice(from,to) 返回制定数组的一个片段会子数组,即截取 。slice()方法不修改原数组。
     splice(first,count,[args]) 在数组中插入或替换或删除的通用方法。
     pop() push()一个是删除队尾元素并返回删除元素一个是在队尾添加一个元素。两个方法都修改并替换原始数组。
     unshift() shift() 类似于pop() push() 只是在首部执行。unshift() 传人多参数是一次性插值,则顺序与参数顺序一致。
     toString() toLocalString() 不多说跟join方法类似。
     

ECMAScript5中 的数组方法

     forEach(f(v,i,a)) 遍历数组的方法,需要注意的是。无法在遍历完成之前终止遍历,只能采用异常语句的形式break;
     map(f(v,i,a) ) 将调用数组的每个元素传递给调用函数,并返回一个数组。此函数应有返回值,
     filter(f())  filter会跳过稀疏数组中缺少的元素,返回的总是稠密数组。
     every() some()  对数组元素应有指定的函数进行判定并返回true或false;不同的是every() 在匹配到第一个false停止遍历,而some() 是在匹配到第一个true则停止遍历,对待空数组上,every() 返回true而some()返回false;
     reduce(f(),[initValue,thisAgr]) reduceRight() 使用指定函数将数组元素进行组合,生成单个值。需要注意的事此处数组的三个参数是作为第2~4个参数传人函数的。
     index() lastIndexOf() 搜索数组中给定值的具体位置
     

数组类型和类数组类型

     下面提供两个检测方法
/**检查对象的类属性来判断是不是数组**/var isArray = Function.isArray || function (o) {return typeof o === "object" &&Object.prototype.toString.call(o) === "[Object Array]";}/**检测类数组对象**/function isArrayLike(o) {if(o && typeof o === "object" &&isFinite(o.length) &&o.length >= 0 &&o.length === Math.floor(o.length) &&o.length < 2^32 )return true;else return false;}
并且在使用类数组类型时使用数组的特有方法的兼容模式处理.
//类数组对象调用数组方法兼容模式Array.join = Array.join || function(a,sep) {return Array.prototype.join.call(a,sep);};Array.slice = Array.slice || function(a,from,to) {return Array.prototype.slice.call(a,from,to);};Array.map = Array.map || function(a,f,thisArg) {return Array.prototype.map.call(a,f,thisArg);};Array.filter = Array.filter || function(f) {return Array.prototype.filter.call(f);};Array.reduce = Array.reduce || function(f,d,v,i,a) {return Array.prototype.reduce.call(f,d,v,i,a);};

作为数组的字符串

      记住一点:字符串是不可变的。所以当做数组对象是,只是只读,而不可改写。push() sort() slice() 这种改变数组的方法对字符串是无效的。使用数组方法来修改字符串会导致错误,而且出错的时候没有提示











0 0