最近在练习JavaScript题目时发现有些实现自己立即并不能想出来,而且有些常见的方法的用法理解是有错误的如parseInt,所以记录一下。这是第四篇,定要温故而知新 。^_^
安全的类型检测
最安全的方法
1 2 3
| isType(param,type){ return Object.prototype.toString.call(param) === '[object '+type+']' }
|
也可以用这种方法来检测是否是原生的JSON
1
| isNativeJSON = window.JSON && Object.prototype.toString.call(JSON) === '[object JSON]'
|
作用域安全的构造函数
当使用构造函数创建实例时若是没有使用new关键字,则会使得this指向window对象,会意外给window 对象增改属性。
改进: 增加this的类型检测
1 2 3 4 5 6 7 8
| function Person(name,age){ if(this instanceof Person){ this.name = name this.age = age }else{ return new Person(name,age) } }
|
但是这种情况在只使用构造函数进行继承时会出现错误。 如以下的例子:
1 2 3 4 5 6 7 8 9 10 11 12
| function Person(name,age){ if(this instanceof Person){ this.name = name this.age = age }else{ return new Person(name,age) } } function Student(sex,name,age){ Person.apply(this,name,age) this.sex = sex }
|
这时如果使用Student去创建实例,则会只有sex 属性和一个person的实例
改进二: 使用继承来解决上述问题
1 2 3 4 5 6 7 8 9 10 11 12 13
| function Person(name,age){ if(this instanceof Person){ this.name = name this.age = age }else{ return new Person(name,age) } } function Student(sex,name,age){ Person.apply(this,name,age) this.sex = sex } Student.prototype = new Person()
|
惰性载入函数
惰性载入即当有一个方法中有多个if 时并且只是进行一些检测之后就只执行其中的一个分支的情况。这种最常见的就是浏览器的类型检测如 在创建XMLHttpRequest 对象时。对于这种经检测只执行其中的一个分支的情况,有两种优化方式:
方法一: 在函数在第一次调用的过程中,该函数会被覆盖为另外一个按合适方式运行的函数。如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function createXHR() { if (typeof XMLHttpRequest !== 'undefined') { createXHR = function () { return new XMLHttpRequest() } } else if (typeof ActiveObject !== 'undefined') { createXHR = function () { return new ActiveObject('Microsoft.XMLHTTP'); } } else { throw new Error('NO XHR object Available') } return createXHR() }
|
方法二: 使用IIFE — 在声明函数时就指定适当的函数。这种情况下第一次调用函数不会损失性能,而在代码首次加载时会损失一点性能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var createXHR = (function () { if (typeof XMLHttpRequest !== 'undefined') { return function () { return new XMLHttpRequest() } } else if (typeof ActiveObject !== 'undefined') { return function () { return new ActiveObject('Microsoft.XMLHTTP'); } } else { return function () { throw new Error('No XHR Object available') } } })()
|
防篡改对象
定义防篡改对象是为了防止代码无意被修改,但是需注意的是 一旦把对象定义为防篡改,就无法撤销了。
首先是关于对象的属性的属性描述符。对于对象的属性 可以使用Object.defineProperty(对象名,属性名)获取到,共有 value、writable、enumerable和configurable四种属性值。只有configurable是true时,才可以使用defineProperty()来修改属性描述符,并且configurable修改成false是单向的,不能修改回去。
设置防篡改对象可以使用下面四种方法:
方法一:使用 writable:false configurable:false 来创建 不可修改、不可重定义、不可删除的 常量属性
方法二:使用Object.preventExtensions(对象名)来禁止一个对象添加新属性
方法三:使用Object.seal(对象名)来密封一个对象。即在一个对象上调用Object.preventExtensions()并把所有的属性标记为 configurable: false ,但是可以更改属性值
方法四:使用Object.freeze(对象名)会冻结一个对象。 就是在Object.seal() 并把所有”数据访问”属性标记为writable: false
这个方法是可以应用在对象的级别的最高的不可变性,但也只是会禁止对象本身及其任意直接属性的修改
JSON.stringify 和 JSON.parse
JSON.stringify(value[,replacer[,space]])
对于replacer可以是函数,也可以是一个数组。如果第二个参数是一个函数,那么序列化过程中的每个属性都会被这个函数转化和处理
如果第二个参数是一个数组,那么只有包含在这个数组中的属性才会被序列化到最终的JSON字符串中
如果第二个参数是null,那作用上和空着没啥区别,但是不想设置第二个参数,只是想设置第三个参数的时候,就可以设置第二个参数为null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var friend={ "firstName": "Good", "lastName": "Man", "phone":"1234567", "age":18 }; var friendAfter=JSON.stringify(friend,function(key,value){ if(key==="phone") return "(000)"+value; else if(typeof value === "number") return value + 10; else return value; }); console.log(friendAfter);
|
JSON.stringify() 在序列化过程中会依据一些规则进行优化,会产生一些”意外”的情况,需要注意。