ES6-Object‘s Extends

依赖文件地址 :https://github.com/chanceLe/ES6-Basic-Syntax/tree/master/js

  1 <!DOCTYPE html>
  2 <html>
  3     <head>
  4         <meta charset="UTF-8">
  5         <title>[es6]-08-对象的扩展</title>
  6         <script src="./js/browser.js"></script>
  7         <script type="text/babel">
  8             /*
  9              *  对象的扩展
 10              */
 11             
 12             /*属性的简洁表示法
 13              * ES6允许直接写入变量和函数,作为对象的属性和方法。
 14              * 这样书写更加简洁。
 15             */
 16             
 17             var foo = 'bar';
 18             var baz = {foo};
 19             console.log(baz);
 20             //等同于
 21             
 22             var baz2 = {foo:foo};
 23             /*
 24              * 上面代码表明,ES6允许在对象之中,只写属性名,不写属性值。
 25              * 这时,属性值等于属性名所代表的变量。下面还有个例子:
 26              */
 27             function f(x,y){
 28                 return {x,y}
 29             }
 30             //等价于
 31             function f1(x,y){
 32                 return {x:x,y:y}
 33             }
 34             console.log(f(1,2));
 35             // 方法也可以简写
 36             var o = {
 37                 method(){
 38                     return "hello!";
 39                 }
 40             }
 41             console.log(o.method());   //hello!
 42             //下面是一个实际的例子
 43             var birth = '2000/01/01';
 44             var Person = {
 45                 name:"zhangdan",
 46                 birth,
 47                 hello(){
 48                     console.log("my name is ",this.name);
 49                 }
 50             }
 51             Person.hello();
 52             //这种写法用于函数的返回值,将会非常方便。
 53             function getPoint(){
 54                 var x=1;
 55                 var y=10;
 56                 return {x,y};
 57             }
 58             console.log(getPoint());
 59             
 60             //CommonJS模块输出变量,就非常合适使用简洁写法。
 61             var ms = {};
 62             function getItem(key){
 63                 return key in ms? ms[key]:null;
 64             }
 65             function setItem(key,value){
 66                 ms[key] = value;
 67             }
 68             function clear(){
 69                 ms = {};
 70             }
 71             //module.exports = {getItem,setItem,clear};
 72             //等价于
 73             /*module.exports = {
 74                 getItem:getItem,
 75                 setItem:setItem,
 76                 clear:clear
 77             }
 78             */
 79             //注意简洁写法的属性名总是字符串,这会导致一些看上去比较奇怪的结果。
 80             var obj = {
 81                 class(){
 82                     console.log("class");
 83                 }
 84             }
 85             //上面代码中,class是字符串,所以不会因为它属于关键字,而导致语法解析报错。
 86             //如果某个方法的值是一个Generator函数,前面需要加上星号。
 87             /*
 88             var obj = {
 89                 * m(){
 90                     yield "hello world!";
 91                 }
 92             }
 93             console.log(obj.m(),"haha");
 94             */
 95             //上面的代码中,报错???
 96             
 97             /*
 98              * 属性名表达式
 99              * js语言定义对象的属性,有两种方法:
100              * obj.foo = true;
101              * obj["a"+"bc"] = 123;
102              * 方法一直接用标识符作为属性名,方法二是用表达式作为属性名,这时要将表达式放在[]内。
103              * 但是,如果使用字面量方式定义对象(使用大括号),在es5中只能使用方法一(标识符)定义属性。
104              * 
105              * es6允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在[]内。
106              */
107             let propKey = "foo";
108             let obj2 = {
109                 [propKey]:true,
110                 ['a'+'bc']:123
111             }
112             console.log(obj2);
113             //表达式还可用于定义方法名。
114             let obj3={
115                 ["h"+"ello"](){
116                     return "hi";
117                 }
118             }
119             console.log(obj3.hello());
120             //属性名表达式与简洁表示法,不能同时使用会报错。
121             
122             /*
123              * 方法的name属性
124              * 函数的name属性,返回函数名。对象方法也是函数,因此也有name属性。
125              */
126             var person = {
127                 sayName(){
128                     console.log(this.name);
129                 },
130                 firstName(){
131                     return "nicholas"
132                 }
133             }
134             console.log(person.sayName.name);
135             console.log(person.firstName.name);
136             //上面代码中,方法的name属性返回函数名。
137             //如果使用了取值函数,则会在方法前加上get,
138              // 存值函数,会加上set。(但是,实际上,我并没能分出来这个区别。)
139              
140              //两种特殊情况:bind方法创造的函数,name属性返回bound+函数名,
141              //             Function构造函数创造的函数,name属性返回anonymous。
142              console.log((new Function()).name);  //anonymous。
143              var doSomething = function(){} 
144              console.log(doSomething.bind().name);  //bound doSomething
145              
146              //如果对象的方法是一个Symbol值,namname属性返回这个Symbol值的描述。
147              const key1 = Symbol("description");
148              const key2 = Symbol();
149              let obj4 = {
150                  [key1](){},
151                  [key2](){}
152              }
153              console.log(obj4[key1].name);  //''
154              console.log(obj4[key2].name);  //''
155              //事实上,打出来是完全一样的,???
156              
157              /*
158               * Object.is()
159               * es5可以通过下面的代码,部署Object.is()
160               */
161              Object.defineProperty(Object,"is",{
162                  value:function(x,y){
163                      if(x===y){
164                          //针对+0不等于-0的情况
165                          return x!==0 || 1/x === 1/y;
166                      }
167                      //针对NaN的情况
168                      return x !==x && y!==y;
169                  },
170                  configurable:true,
171                  enumerable:false,
172                  writable:true
173              })
174              
175              /*
176               * Object.assign()
177               * 该方法用于对象的合并,将源对象的所有可枚举属性,复制到目标
178               * 对象。
179               * 第一个参数是目标对象,剩下的参数都是源对象。
180               * 如果有同名属性,后面的属性会覆盖前面的属性。
181               * 如果只有一个参数,就返回这个参数。如果这个参数不是对象,会先转换成对象。
182               * 由于undefined和null无法转成对象,所以他们作为参数会报错。
183               * 
184               * 如果非对象出现在源对象的位置(即非首参数),首先这些参数都会转成对象,如果
185               * 无法转成对象,就会跳过。这意味着如果undefined和null不在首参数,就不会报错。
186               * 
187               * 其他类型的值,不在首参数也不会报错,但只有字符串会合入目标对象,数值和布尔值都会被
188               * 忽略,因为只有字符串的包装对象会产生可枚举的实义属性。数值和布尔值转成的包装对象
189               * 他们的原始值都存放在[[PrimitiveValue]]:"false"属性中。不会被Object.aasign()拷贝。
190               * 
191               * Object.assgn()不拷贝继承属性,也不拷贝不可枚举属性(enumerable:false)
192               */
193              var target = {a:1};
194              var source1 = {b:2};
195              var source2 = {c:3};
196              var source3 = {b:5};
197              Object.assign(target,source1,source2,source3);
198              console.log(target);
199              console.log(Object.assign(target) === target);  //true
200              
201              console.log(Object.assign({a:"b"},{[Symbol("c")]:"d"}));
202              //结果显示属性名为Symbol值的属性,也会被Object.assign拷贝。
203              
204              //注意点,Object.assign()方法实行的是浅拷贝,也就是说,如果属性值是一个对象,那么目标对象拷贝到的
205              //是这个对象的引用。
206              //对于嵌套的对象,一旦遇到同名属性,Object.assign()的处理方法是替换,而不是添加。
207              
208              //Object.assign()可以用来处理数组,但是会把数组当做对象,并且一定会覆盖索引相同的值.
209              console.log(Object.assign([1,2,3],[4,5]));   //[4,5,3]
210              
211              /*
212               * 用途: 1.为对象添加属性  2.为对象添加方法  3.克隆对象
213               * 4.将多个对象合并到某个对象。
214               * 5.为属性指定默认值,这个跟jquery插件开发的那个东西一样。
215               */
216              function clone(origin){
217                  return Object.assign({},origin);
218              }
219              //上面代码将原始对象拷贝到一个空对象,就得到了原始对象的克隆。不过上面这种不能克隆继承的值,如果
220              //要保持继承链,可以用下面的代码:
221              
222              function clone2(origin){
223                  let originProto = Object.getprototypeOf(origin);
224                  return Object.assign(Object.create(originProto),origin);
225              }
226              
227              
228              /*
229               * 属性的可枚举性。
230               * 对象的每个属性都有一个描述对象,用来控制该属性的行为。
231               * Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。
232               */
233              let obj5 = {foo:123};
234              console.log(Object.getOwnPropertyDescriptor(obj5,'foo'));
235              /*
236               * 描述对象的enumerable就是可枚举性,es5有三个操作会忽略enumerable:false的属性:
237               * for...in...循环:只遍历对象自身的和继承的可枚举属性。
238               * Object.keys() 返回对象自身的所有可枚举属性的键名
239               * JSON.stringify():只串行化对象自身的可枚举属性
240               * 
241               * ES6新增的Object.assign会忽略enumerable:false的属性。
242               * 这四个操作中,只有for...in...会返回继承的属性。
243               * 另外,ES6规定,所有class的原型的方法都是不可枚举的。
244               */
245              let k = Object.getOwnPropertyDescriptor(class {foo(){}}.prototype,"foo").enumerable;
246              console.log(k);  //false  
247              
248              //总的来说,操作中引入继承的属性会让问题复杂化,大多数时候,我们只关心对象自身的属性。
249              //所以,尽量不要用for...in...循环,而用Object.keys()代替。
250              
251              /*
252               * 属性的遍历
253               * ES6一共有5种方法遍历对象的属性。
254               * 1.for...in   :循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)。
255               * 2.Object.keys(obj) : 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性)。
256               * 3.Object.getOwnpropertyNames(obj)  :返回一个数组,包含对象自身的所有属性(不含Symbol属性,但是包括不可枚举属性)。
257               * 4.Object.getOwnPropertySymbols(obj)  : 返回一个数组,包含对象自身的所有Symbol属性。
258               * 5.Reflect.ownKeys(obj)  :返回一个数组,包含对象自身的所有属性,不管属性名是Symbol或字符串,也不管是否可枚举。
259               * 
260               * 以上5种方法遍历对象的属性,都遵守同样的属性遍历次序规则:
261               *  首先遍历所有属性名为数值的属性,按照数字排序。
262               *   其次遍历所有属性为字符串的属性,按照生成时间排序。
263               *    最后遍历所有属性名为Symbol值的属性,按照生成时间排序。
264               * 下面有个例子:
265               */
266              let m = Reflect.ownKeys({[Symbol()]:0,b:0,10:0,2:0,a:0});
267              console.log(m);  //结果体现了遍历的次序规则。
268              
269          //_proto__属性,Object.setPrototypeOf()和Object.getprototypeOf()    
270              /*
271               * __proto__属性,用来设置或读取当前对象的prototype对象。目前所有浏览器(包括IE11)都部署了这个属性。
272               */
273              
274              /*
275              //es6的写法
276              var obj6 = {
277                  method(){}
278              }
279              obj6.__proto__ = someOtherObj;
280              
281              //es5的写法
282              var obj7 = Object.create(someOtherObj);
283              obj.method = function(){}
284              */
285              /*
286               * 该属性没有写入es6的正文,而是写入了附录,原因是双下划线说明它本质上是一个内部属性。而不是一个正式的对外的API,
287               * 只是由于浏览器的广泛支持,才被加入ES6。标准明确规定,只有浏览器必须部署这个属性,其他环境不一定要部署,而且新的
288               * 代码最好是认为这个属性不存在的。因此最好不要使用这个属性,而是用下面的Object.setprototypeOf()Object.getprototypeOf()
289               * 和Object.create()代替。
290               * 
291               * 在实现上,__proto__调用的是Object.prototype.__proto__。
292               * 如果一个对象部署了__proto__属性,该属性的值就是对象的原型。
293               */
294              
295              /*
296               * Object.setPrototypeOf()
297               * 作用与__proto__相同,是es6官方推荐的设置对象原型的方法。
298               * 格式: Object.setPrototypeOf(object,prototype);
299               * 下面是一个例子:
300               */
301              let proto = {};
302              let obj8 = {x:10};
303              Object.setPrototypeOf(obj8,proto);
304              proto.y = 20; proto.z = 25;
305              console.log(obj8.x,obj8.y,obj8.z) ;  //10,20,25
306              
307              /*
308               * Object.getPrototypeOf()与上一个配套,用于读取一个对象的prototype对象。
309               */
310              console.log(Object.getPrototypeOf(obj8));  
311         </script>
312     </head>
313     <body>
314     </body>
315 </html>

 

posted @ 2017-07-16 20:26  橙云生  阅读(370)  评论(0编辑  收藏  举报