码迷,mamicode.com
首页 > 其他好文 > 详细

学习第三天(2019-11-16)

时间:2019-11-16 23:46:33      阅读:139      评论:0      收藏:0      [点我收藏+]

标签:prope   无法   cto   UNC   构造   nic   执行环境   初始   修改属性   

第六章 面向对象的程序设计

ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或者函数。”可以把这里的对象想象成散列表:无非就是一组名值对,其中值可以是数据或函数。 

1、对象的属性类型

    ECMAScript中有两种属性:数据属性和访问器属性。

    a:数据属性

        数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性。

         [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特 性,或者能否把属性修改为访问器属性,默认值为 true。

         [[Enumerable]]:表示能否通过 for-in 循环返回属性,默认值为 true。

         [[Writable]]:表示能否修改属性的值,默认值为 true。 

         [[Value]]:包含这个属性的数据值,默认值为 undefined。 

     要修改属性默认的特性,可以使用 ECMAScript 5的Object.defineProperty()方法。这个方法 接收三个参数:属性所在的对象、属性的名字和一个描述符对象。

   b:访问器属性

        访问器属性不包含数据值,它们包含一对儿 getter和 setter函数(这两个函数不是必须的)。在读取访问器属性时,会调用 getter函数,这个函数负责返回有效的值;

        在写入访问器属性时,会调用 setter函数并传入新值,这个函数负责决定如何处理数据。 

        访问器属性有如下 4个特性:

        [[Configurable]]:表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特 性,或者能否把属性修改为访问器属性,默认值为 true。

        [[Enumerable]]:表示能否通过 for-in 循环返回属性,默认值为 true。

        [[Get]]:在读取属性时调用的函数。默认值为 undefined。

        [[Set]]:在写入属性时调用的函数。默认值为 undefined。 

        访问器属性不能直接定义,必须使用 Object.defineProperty()来定义。如下:

 1 var book = { 
 2     _year: 2004,   
 3    edition: 1
 4 }; 
 5  
 6 Object.defineProperty(book, "year", {    
 7     get: function(){        
 8        return this._year;     
 9     }, 
10     set: function(newValue){ 
11        if (newValue > 2004) {    
12           this._year = newValue;   
13           this.edition += newValue - 2004;         
14        }     
15     } 
16 }); 
17  
18 book.year = 2005; 
19 alert(book.edition);  //2 

以上代码创建了一个 book 对象,并给它定义两个默认的属性:_year 和 edition。_year 前面的下划线是一种常用的记号,用于表示只能通过对象方法访问的属性。而访问器属性 year 则包含一个 getter函数和一个 setter函数。getter函数返回_year 的值,setter函数通过计算来确定正确的版本。因此,把 year 属性修改为 2005会导致_year 变成 2005,而 edition 变为 2。这是使用访问器属性的常见方 式,即设置一个属性的值会导致其他属性发生变化。 

使用 ECMAScript 5的Object.getOwnPropertyDescriptor()方法,可以取得给定属性的描述符。

 

2、创建对象

     ECMAScript支持面向对象(OO)编程,但不使用类或者接口。对象可以在代码执行过程中创建和增强,因此具有动态性而非严格定义的实体。在没有类的情况下,可以采用下列模式创建对象。

  a:工厂模式,使用简单的函数创建对象,为对象添加属性和方法,然后返回对象。这个模式后来被构造函数模式所取代。

  b:构造函数模式,可以创建自定义引用类型,可以像创建内置对象实例一样使用 new 操作符。不过,构造函数模式也有缺点,即它的每个成员都无法得到复用,包括函数。       由于函数可以不局限于任何对象(即与对象具有松散耦合的特点),因此没有理由不在多个对象间共享函数。

  c:原型模式,使用构造函数的 prototype 属性来指定那些应该共享的属性和方法。(重点理解原型的概念)

  d:组合使用构造函数模式和原型模式时,使用构造函数定义实例属性,而使用原型定义共享的属性和方法,结合了两者的优点。

      组合使用构造函数模式和原型模式代码:

 1 function Person(name, age, job){     
 2   this.name = name;     
 3   this.age = age;     
 4   this.job = job;     
 5   this.friends = ["Shelby", "Court"]; 
 6 } 
 7  
 8 Person.prototype = {     
 9   constructor : Person,
10   sayName : function(){         
11     alert(this.name);     
12   } 
13 } 
14  
15 var person1 = new Person("Nicholas", 29, "Software Engineer"); 
16 var person2 = new Person("Greg", 27, "Doctor"); 
17  
18 person1.friends.push("Van");
19 alert(person1.friends);    //"Shelby,Count,Van" 
20 alert(person2.friends);    //"Shelby,Count" 
21 alert(person1.friends === person2.friends);    //false 
22 alert(person1.sayName === person2.sayName);    //true 
//在这个例子中,实例属性都是在构造函数中定义的,
//而由所有实例共享的属性 constructor 和方法 sayName()则是在原型中定义的。
//而修改了 person1.friends(向其中添加一个新字符串),
//并不会影响到 person2.friends,因为它们分别引用了不同的数组。

这种构造函数与原型混成的模式,是目前在 ECMAScript中使用广泛、认同度高的一种创建自 定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。

 e:动态原型模式、它把所有信息都封装在了构造函数中,而通过在构造函数中初始化原型(仅在必要的情况下),又保持了同时使用构造函数和原型的优点。

 f:其他方法还有:寄生构造函数模式 、稳妥构造函数模式 

 

3、继承

JavaScript 主要通过原型链实现继承。

原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的。这样,子类型就能够访问超类型的所有属性和方法,这一点与基于类的继承很相似。 原型链的问题是对象实例共享所有继承的属性和方法,因此不适宜单独使用。

解决这个问题的技术是借用构造函数,即在子类型构造函数的内部调用超类型构造函数。这样就可以做到每个实例都具有自己的属性,同时还能保证只使用构造函数模式来定义类型。

使用较多的继承模式是组合继承,这种模式使用原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。

 

  组合继承大的问题就是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

此外,还存在下列可供选择的继承模式:

 原型式继承,可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制。而复制得到的副本还可以得到进一步改造。

 寄生式继承,与原型式继承非常相似,也是基于某个对象或某些信息创建一个对象,然后增强对象,后返回对象。

 寄生组合式继承,集寄生式继承和组合继承的优点与一身,是实现基于类型继承的有效方式,解决了组合继承模式由于多次调用超类型构造函数而导致的低效率问题。

 

第七章 函数表达式

函数表达式特点:

1、函数表达式不同于函数声明。函数声明要求有名字,但函数表达式不需要。没有名字的函数表 达式也叫做匿名函数。

2、 递归函数应该始终使用 arguments.callee 来递归地调用自身,不要使用函数名——函数名可 能会发生变化。

3、当在函数内部定义了其他函数时,就创建了闭包。闭包有权访问包含函数内部的所有变量,原理如下:

   a、在后台执行环境中,闭包的作用域链包含着它自己的作用域、包含函数的作用域和全局作用域。
   b、通常,函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,当函数返回了一个闭包时,这个函数的作用域将会一直在内存中保存到闭包不存在为止。 使用闭包可以在 JavaScript中模仿块级作用域(JavaScript本身没有块级作用域的概念)。

4、 即使 JavaScript中没有正式的私有对象属性的概念,但可以使用闭包来实现公有方法,而通过公 有方法可以访问在包含作用域中定义的变量。

5、 有权访问私有变量的公有方法叫做特权方法。

6、 可以使用构造函数模式、原型模式来实现自定义类型的特权方法,也可以使用模块模式、增强 的模块模式来实现单例的特权方法。 JavaScript 中的函数表达式和闭包都是极其有用的特性,利用它们可以实现很多功能。不过,因为 创建闭包必须维护额外的作用域,所以过度使用它们可能会占用大量内存。

 

 

 

 

 

学习第三天(2019-11-16)

标签:prope   无法   cto   UNC   构造   nic   执行环境   初始   修改属性   

原文地址:https://www.cnblogs.com/xiaoxb17/p/11874153.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!