[TOC]
>[success] # Javascript 面向对象编程(一):封装
在写之前先发一下参考大佬阮一峰的文章地址 [Javascript 面向对象编程(一):封装](http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html) 因为是参考大佬的案例总结知识嘛。
>[success] ## 一、 生成实例对象的原始模式
那么什么是实例对象? 实例和对象的区别,从定义上来讲:
* 1、实例是类的具象化产品,(例如猫是一个种类)
* 2、而对象是一个具有多种属性的内容结构(猫有名字、颜色、大小,这些都是猫的属性)
~~~
假定我们把猫看成一个对象,它有"名字"和"颜色"两个属性。
var Cat = {
name : '',
color : ''
}
但是我现在如果有2个猫就要写成这样的:
var cat1 = {}; // 创建一个空对象
cat1.name = "大毛"; // 按照原型对象的属性赋值
cat1.color = "黄色";
var cat2 = {};
cat2.name = "二毛";
cat2.color = "黑色";
~~~
<br/>
>[success] ## 二、 原始模式的改进
那么如果有100个猫我岂不是累死了,要写100个对象? 不那样太傻了于是做了一些改进如下,这种方法的问题依然是,'cat1'和'cat2'之间没有内在的联系,不能反映出它们是同一个原型对象的实例。
~~~
// 封装一个函数这样就可以有好多猫
function Cat(name,color) {
return {
name:name,
color:color
}
}
调用这样写:
var cat1 = Cat("大毛","黄色");
var cat2 = Cat("二毛","黑色");
~~~
<br/>
>[success] ## 三、 构造函数模式
为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。
所谓"构造函数",其实就是一个普通函数,但是内部使用了[`this`变量](http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html)。对构造函数使用`new`运算符,就能生成实例,并且`this`变量会绑定在实例对象上。
~~~
比如,猫的原型对象现在可以这样写:
// 这个就是构造函数
function Cat(name,color){
this.name=name;
this.color=color;
this.age = "1"
}
然后页面中调用这个实例对象这么写:
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.name); // 大毛
alert(cat1.color); // 黄色
这个new Cat()的写法我的理解,就是深拷贝下来这个Cat构造函数中的属性值,如果cat1修改了Cat构造函数中的属性值cat2不会受到
影响例如:
var cat1 = new Cat("大毛","黄色")
var cat2 = new Cat("二毛","黑色");
cat1.age = "2" // "2"
cat2.age // "1"
这时'cat1'和'cat2'会自动含有一个'constructor'属性,指向它们的构造函数。
alert(cat1.constructor == Cat); // true
alert(cat2.constructor == Cat); // true
alert(cat1.constructor == cat2.constructor) // true
Javascript还提供了一个'instanceof'运算符,验证原型对象与实例对象之间的关系。
alert(cat1 instanceof Cat); //true
alert(cat2 instanceof Cat); //true
~~~
<br/>
>[success] ## 四、构造函数模式的问题
~~~
构造函数方法很好用,但是存在一个浪费内存的问题。
请看,我们现在为'Cat'对象添加一个不变的属性'Cat'(种类),再添加一个方法'eat'(吃)。那么,原型对象'Cat'就变成了下面
这样:
function Cat(name,color){
this.name = name;
this.color = color;
this.type = "猫科动物";
this.eat = function(){alert("吃老鼠");};
}
表面上好像没什么问题,但是实际上这样做,有一个很大的弊端。那就是对于每一个实例对象,'type'属性和'eat()'方法都是一模一样
的内容,每一次生成一个实例,都必须为重复的内容,多占用一些内存。这样既不环保,也缺乏效率。
alert(cat1.eat == cat2.eat); // false
能不能让'type'属性和'eat()'方法在内存中只生成一次,然后所有实例都指向那个内存地址呢?回答是可以的。
~~~
<br/>
>[success] ## 五、 Prototype模式
~~~
Javascript规定,每一个构造函数都有一个'prototype'属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例
继承。这意味着,我们可以把那些'不变的属性和方法',直接定义在'prototype'对象上。
function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){alert("吃老鼠")};
然后,生成实例。
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠
这时所有实例的'type'属性和'eat()'方法,其实都是同一个内存地址,指向'prototype'对象,因此就提高了运行效率。
alert(cat1.eat == cat2.eat); //true
~~~
<br/>
>[success] ## 六、 Prototype模式的验证方法
~~~
为了配合'prototype'属性,Javascript定义了一些辅助方法,帮助我们使用它
6.1 isPrototypeOf()
这个方法用来判断,某个'proptotype'对象和某个实例之间的关系。
alert(Cat.prototype.isPrototypeOf(cat1)); //true
alert(Cat.prototype.isPrototypeOf(cat2)); //true
6.2 hasOwnProperty()
每个实例对象都有一个'hasOwnProperty()'方法,用来判断某一个属性到底是本地属性,还是继承自'prototype'对象的属性。
alert(cat1.hasOwnProperty("name")); // true
alert(cat1.hasOwnProperty("type")); // false
6.3 in运算符
'in'运算符可以用来判断,某个实例是否含有某个属性,不管是不是本地属性。
alert("name" in cat1); // true
alert("type" in cat1); // true
'in'运算符还可以用来遍历某个对象的所有属性。
for(var prop in cat1) { alert("cat1\["+prop+"\]="+cat1\[prop\]); }
~~~
- Javascript基础篇
- Array数组
- 数组插入值
- filter()
- forEach()
- push()
- pop()
- unshift()
- shift()
- valueOf()
- 面向对象思想
- Javascript 面向对象编程(一):封装
- Javascript面向对象编程(二):构造函数的继承
- Javascript面向对象编程(三):非构造函数的继承
- 解构
- 数组的解构赋值
- 对象的解构赋值
- 函数参数解构
- 字符串的解构赋值
- 数值和布尔值的解构赋值
- 圆括号问题
- 字符串.
- split()
- charAt()
- charCodeAt()
- concat()
- indexOf()
- lastIndexOf()
- match()
- replace()
- includes()
- 初识递归
- 渲染ul-li树形结构
- 异步函数解决方案
- 1. callback回调函数
- 2. ES6 - Promise
- JavaScript高级程序设计(书)
- 在html中使用JavaScript
- script标签的位置
- 延迟脚本
- 异步脚本
- <noscript>元素
- 基本概念
- 严格模式
- 变量详解
- 数据类型
- typeof操作符
- undefined类型
- Null类型
- Boolean类型
- Number类型
- 深入了解ES6(书)
- var 、let 、 const
- 字符串与正则表达式
- 字符串
- 正则表达式
- 函数
- 函数形参默认值
- 使用不具名参数
- 函数构造器的增强能力
- 扩展运算符
- name属性
- 明确函数的多重用途
- 块级函数
- 箭头函数
- 尾调用优化
- 扩展的对象功能
- 对象类别
- 对象字面量语法的扩展
- ES6对象新增方法
- 重复的对象属性
- 自有属性的枚举顺序
- 更强大的原型
- 解构:更方便的数据访问
- 为什么要用解构?
- 对象解构
- 数组解构
- 混合解构
- 参数解构
- Symbol与Symbol属性
- 创建Symbol
- Symbol的使用方法
- Symbol全局私有属性
- Symbol与类型强制转换
- Symbol属性检索
- Symbol的一些构造方法
- Set集合与Map集合
- Set集合
- Weak Set集合(弱引用Set集合)
- Map集合
- JS标准内置对象
- Object 构造函数及属性
- Object 构造方法
- Symbol 内建对象类的函数及属性
- Set 构造函数及属性
- Weak Set 构造函数及属性
- JS杂项
- 类数组对象
- Class类的理解和使用