红宝书 第6章整理——创建对象
来源:互联网 发布:python处理ajax请求 编辑:程序博客网 时间:2024/05/20 08:25
1、理解对象+对象属性
面向对象语言有一个标志,就是他们都有类的概念。通过类来创建多个具有相同属性的方法和对象。但是!!!js中没有类的概念,所以js中所谓的面向对象有些不同。
js中的对象可以理解成一组组的名值对(属性 + 值),其中的值可以是数据或者函数。每个对象都是基于一个引用类型创建的,详见第5章。
创建对象可以直接用原生类型(new array,new function....) 也可以自己创建(new object)
属性
1、分类
对象的属性,可以分为两种:数据属性、访问器属性1、数据属性
即在对象中显式的写出来的属性。可以用Object.defineProperty()函数来对其进行设置,例如该属性是否可删除,可修改等等var person = { };
Object.defineProperty(person,"name",{
writable:false, //设置不可写,就是只读的
value:"jack"});
writeable(只读),configurable(删除,注意这个属性一旦改成了false就改不回来了),enumerable(可列举)
若想同时该多个属性的设置,可用defineProperties()函数。
2、访问器属性
这种属性不在对象定义中显式的写出来,而且该属性都是方法函数,不是值。只能通过Object.defineProperty()函数来设置,有点像后台处理的方法有get和set可以设置,分别对应写入时和读取时的操作。
2、创建对象
当要写一个类来创建多个对象时:分类:工厂模式
构造函数模式
原型模式
组合使用(构造+原型)
动态原型模式
.....
① 工厂模式:
“工厂模式” 是一种设计模式,就是把创建过程整个进行封装,直接上代码:
function creatPerson(name , age){ var o = new Object(); o.name = name; o.age = age; o.say = function(){ alert(this.name);}; return o;}var person1 = creatPerson(jack,20);var person2 = creatPerson(tom.30);
可以看出来在这种模式下,是最无脑的简单的批量创建方法,但是最大的问题是这样创建的对象仅仅属于Object的实例,算是原生对象的实例,不算是用户自定义的类的实例。
所以进行改进——构造函数模式
② 构造函数模式
function Person (name , age) { this.name = name; this.age = age; this.say = function(){ alert (this.name);};}var person1 = new Person(jack,20);var person2 = new Person(tom.30);
改进之处:
1、在function中没有显示的创建对象,即new object() ,在想创建对象时再new
2、在function中用this来指代对象(因为function中没有显式创建)
3、function中不用return
4、函数名一般开头字母大写,算是惯例
优点:
1、 这种方法创建的实例算是自定义类的实例,此时person1 与person2 不仅仅是object的实例,还是Person的实例 。(所有对象都要继承自object啊)
2、不算优点的优点,构造函数还可以当成普通函数用。
当构造函数用时,要new来创建
当普通函数时,不加new,直接Person(jack,20); 此时函数变成了全局函数,this指代的是window,所以window会被添加name,age。
当普通函数用时,就可以配合call,apply来调用,比如作用在一个对象上,也相当于为这个对象添加 了Person的属性和方法
缺点:
每次实例化,函数中所有的属性和方法都会被重新实例化——即每个新对象中的name,age,function say,都是彼此不同的,不会互相干扰。
对于属性来说可能这点是好处,这样可以对每个不同的对象进行后续的修改
但是对于方法来说不好,每次完成同样功能,但是却每次都被重置
一个改进:
把类中的方法拿到构造函数外面写。
function Person(name,age) { ... ... var say = this.say; //在构造函数内部只声明不实现}function say(){ alert(this.name);}
这样就可以避免方法也跟着被重置了。
但是!!! 还是不好!! 当类中有很多方法时,全放到外面写,就破坏了对象的封装性
继续改进——原型模式
③ 原型模式
关键词:共享
我们创建一个函数都会自带一个prototype(原型)属性,这个属性是一个指针,指向这个函数的原型对象。
这样的话,我们给对象的原型添加的属性,方法,在实例化的时候就可以被继承共享了。
function Person(){} //不必在构造函数中定义任何属性,方法Person.portotype.name = "jack"; //在构造函数外面,用prototype添加Person.portotype.age = 20;Person.portotype.say = function(){ alert(this.name);};var person1 = new Person();var person2 = new Person();
此时person1 与person2 所有的属性,方法,全是指向同一个,即原型对象中的name,age,function say。
1、理解原型对象
函数的原型对象最初都有一个属性:constructor。 (默认是不可枚举的,就是在for-in中不会被列出)
这个属性代表这个原型对象的构造函数,可以显式的设置一下,例如Person.prototype.constructor = Person。 双重保障。
用prototype方法添加的属性,方法,实际上都不属于Person类,但是new Person的实例可以用,这是因为会自动向上索引。Person中没有,会自动往上原型类中找。Person中有,则用它的。
若用户为Person类添加了与prototype类中同名的属性,方法,那么调用时会优先用Person类的值。 注意prototype中的值没有变,当Person类中这个属性被delete时,还是会向上索引至prototype类。
2、in操作符
单独使用:
语法: “属性” in 对象 // “name” in person1;
返回:只要这个属性在这个对象中能调用,就返回true。无论它是在Person中,还是在Person.prototype中
for-in
会返回所有通过这个对象能使用的,可枚举(之前说过可以将enumerated = false)的属性。无论Person还是Person.prototype中的
3、简化写法
利用字面量的写法
function Person(){}Person.prototype = { name:"jack", age:20, say: function(){ alert(this.name); };}
缺点:
这种写法实际上完全重写了prototype对象,这导致了constructor属性不会指向原Person类,此时值没有了。 虽然这对创建对象没什么影响,但是若使用顺序颠倒时,会出错,详见下面的动态性。
如果constructor的值很重要,那么可以在字面量中显式的添加 constructor:Person,此时constructor会变为可枚举的,在for-in中可见。注意,即使用constructor写了指向Person,这个Person也是新Person,非原来的!!这种方法就是会切断,连接不回来!!
4、原型的动态性
当不用字面量方法简写时,创建对象可以放在创建类的前面。因为js中实际没有类的概念,是索引,遇到创建对象它会自动在上下文索引。
但是当用字面量方法简写时,顺序就不能颠倒了,因为会重新创建一个Person类。
5、原生对象的原型
prototype不仅仅可以用在自定义的类,还可以用在原生的类中,比如array,string。
可以为他们添加新方法。 Array.Prototype.newmethod = function(){....};
6、优缺点
① 由于在prototype中统一设置属性和值,导致所有实例在默认状况下初始化的值都一样② 最大的问题:引用类型值的原型属性会被所有实例共享。即,若属性的值时引用类型,例如数组时,当有一个实例化对象对其进行修改,那么prototype中的值也会被修改,其他实例化的这个属性也会被改。 之前说的不改的情况是普通数值类型值。
但是prototype的共享,特别适用于对象的方法,即函数,但是并不适合属性,即值。
所以继续改进——组合使用
④组合使用(构造+原型)
这种方式是用户创建自定义类型最常见的。
用构造函数方法定义属性——构造函数式每一次实例化都会为不相同的,所以各个实例的属性可以再次自由定义
用原型模式定义方法 + 一些可以共享(即不做个性化设置的)属性——原型模式对于方法共享,每次实例化不用重新创建,节省内存。
//构造函数中的属性可以被分别再赋值function Person(name , age , job){ this.name = name; this.age = age;} //原型模式中的方法可以被共享Person.prototype = { constructer : Person; //保险起见,可以显式的写一下归属 say : function(){ alert(this.name);}}
优点:
节省内存,集两个方法的优点于一身
缺点:
其实没啥缺点,硬要说的话就是把一个类拆成了两段写,不方便看。所以又有了进一步的改进——动态原型模式
⑤动态原型模式
由于之前分段写不好看,这个模式其实就是简单的把这两段(构造函数部分+原型模式部分)捏在了一起。
通过一个if语句判断。如果对象中没有该方法,就用原型模式创建一个,接下来每次再实例化的时候继续判断,如果已经有了这个方法,就不再创建了。见下:
function Person(name , age ){ //正常在构造函数中写属性 this.name = name; this.age = age; // 接下来判断,用原型模式加方法 if(typeof this.say != "function"){ //只有初次创建时这个方法不存在,在原型中创建。接下来再创建对象,在原型中已有,就跳过了 Person.prototype.say = function(){ alert(this.name);}}}var friend = new Person("jack", 20);friend.say();
当有多个方法时,判断一个就可以,其他的都在这个方法的判断下添加,反正都是一起在初次被创建。
注意:
在这种方式下,原型模式不可以用简写模式(即字面量重写),因为会重新创建一个Person,与已经写好的name,age分别属于不同的Person,切断了联系。
- 红宝书 第6章整理——创建对象
- 红宝书 第6章整理——继承部分
- 红宝书 第5章整理——引用类型(对象)
- 红宝书 第3章 整理——数据类型+函数入门
- 红宝书 第4章整理——变量+内存管理
- 红宝书 第7章整理——函数+闭包
- 红宝书 第8章整理——BOM
- 红宝书 第9章整理——客户端检测
- 红宝书 第10章整理——DOM
- 红宝书 第11章整理——DOM扩展
- 红宝书 第13章整理——事件
- 红宝书 第14章整理——表单
- 红宝书 第15章整理——canvas
- 红宝书 第17章整理——错误处理
- 红宝书 第18章整理——XML入门
- 红宝书 第18章整理——XML与JS
- 红宝书 第18章整理——XPath
- 红宝书 第10章整理——E4X
- java设计模式--结构模式
- matplotlib可视化基本操作
- 汉字GBK编码-------也叫区位码------本人备注
- 隐藏Android 4.0+平板底部状态栏的方法
- 编写NT服务
- 红宝书 第6章整理——创建对象
- 利用二叉树特性优化省市镇三级联动性能
- 算法提高 逆序排列
- HTML基础篇之超链接a标签
- Python: 实现pkcs7格式数字签名方法_20170407_七侠镇莫尛貝
- Thinkphp框架中将数据输出到Execl封装的方法
- Ridge & LASSO & Elastic Net
- Flume中的TaildirSource
- f:DropDownList