继续第二部分
Object.freeze(obj)
看字面意思就是“把一个对象冻结”。
下面我们来看个简单的例子以作说明:
1 // a person instance 2 var person = { 3 name: 'Andrew', 4 job: 'sales manager' 5 }; 6 7 // before freeze 8 // existing properties maybe be changed or removed, new properties may be added 9 person.name = 'Bruce'; 10 person.age = 30; 11 12 console.log(person.name); // Bruce 13 console.log(person.age); // 30 14 15 // freeze the person 16 Object.freeze(person); 17 18 // isFrozen 19 console.log( Object.isFrozen(person) ); // true 20 21 // after freeze 22 // fail silently, or strict mode throw a TypeError 23 person.name = 'James'; 24 person.age = '35'; 25 person.gender = 'male'; 26 27 console.log(person.name); // Bruce 28 console.log(person.age); // 30 29 console.log(person.gender); // undefined
上面例子的特点是,person对象的属性像name,job,age的值都是“字面值”,并非对象,如果存在一个属性,其值是一个对象呢?
我们再来一个例子:
1 // a person again 2 var person = { 3 name: { 4 firstname: 'Bruce', 5 lastname: 'Lee' 6 }, 7 age: 35, 8 job: 'sales manager', 9 children: ['lucy', 'linda'] 10 }; 11 12 console.log('name:' + person.name.firstname + ' ' + person.name.lastname); // name:Bruce Lee 13 console.log('children:' + person.children); // lucy, linda 14 15 // freeze the person 16 Object.freeze(person); 17 18 // has been frozen! 19 console.log(Object.isFrozen(person)); 20 21 // change name 22 person.name.firstname = 'Andrew'; 23 person.name.lastname = 'Carnegie'; 24 25 // add one more child 26 person.children.push('Tom'); 27 28 console.log('name:' + person.name.firstname + ' ' + person.name.lastname); // name:Andrew Carnegie 29 console.log('children:' + person.children); // lucy, linda, Tom
通过上面的2个例子,我们很容易得出结论。那么我们如何做到“深层”freeze呢。
就要用到一个递归函数,来让里面的每个对象都被freeze:
1 function deepFreeze(o) { 2 var prop, propkey; 3 4 Object.freeze(o); 5 6 for(propkey in o) { 7 prop = o[propkey]; 8 9 if( !o.hasOwnProperty(propkey) || !(typeof prop === 'object') || Object.isFrozen(prop) ) { 10 continue; 11 } 12 // Recursively call deepFreeze 13 deepFreeze(prop); 14 } 15 }; 16 17 // if we use deepFreeze to replace with Object.freeze in the previous example, 18 // then nothing will happen, even person's properties(aka. name, age, children ) are changed
利用的deepFreeze方法,我们就可以把person对象的属性全部“冻结”。
搞清楚Object.freeze的用途后,我们继续来了解下Object.seal
Object.seal(obj)
seal从字面意思上理解有“密封”的意思,我依旧通过例子来说明:
1 // a person again 2 var person = { 3 name: 'Andrew', 4 age: 25, 5 children: ['Tom'], 6 edu: { 7 major: 'computer science', 8 university: 'Yale' 9 } 10 }; 11 12 // before seal 13 // new properties may be added, exisiting properties may be changed or removed 14 person.name = 'Bruce'; 15 person.gender = 'male'; 16 delete person.age; 17 18 // looking up the structure 19 console.dir(person); 20 21 // seal the person 22 Object.seal(person); 23 24 // has been sealed 25 console.log( Object.isSealed(person) ); // true 26 27 // after seal 28 // existing (writable) properties can be changed 29 person.name = 'Jackson'; 30 console.log(person.name); // Jackson 31 32 // or change value through Object.defineProperty 33 Object.defineProperty(person, 'name', {value: 'Ann'}); 34 console.log(person.name); // Anna 35 36 // add one more child 37 person.children.push('lucy'); 38 console.log(person.children); // tom, lucy 39 40 // internal object is still extensible, unless you seal it too (eg. Object.seal(person.edu) ) 41 person.edu.degree = 'master'; 42 console.log(person.edu.degree); // master 43 44 // silently fail or in strict mode throw TypeError 45 // when add or delete property 46 person.job = 'Front End Developer'; 47 delete person.name; 48 // TypeError when add property through Object.defineProperty 49 Object.defineProperty(person, 'job', {value: 'teacher'}); // TypeError
通过上面的例子,我们可以看到,seal一个对象后,使得它不可扩展,但是其属性值(该属性writable为true)是 可以改变的。还有一点就是若其属性是一个对象,姑且叫内部对象吧,那么这个内部对象还是可以进行扩展的,除非写一个递归的deepSeal方法, 这个可以参考上面的deepFreeze
第二部分就到这里,感兴趣的同学可以前往MDN查看,Object.freeze,Object.seal。