面向对象笔记一
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象笔记一相关的知识,希望对你有一定的参考价值。
js 面向对象的基本概念和基本使用方法
- -> js 是不是一个面向对象的语言(众说纷纭)?
- 不是:与传统面向对象的理论语言有矛盾。C#,Java。
- 是:js里面到处都是对象,数组,时间,正则... 和 DOM。也可以像传统面向对象的语言那样用 new 的方式创建对象
- -> js是一个基于对象的多范式编程语言。
- 面向过程的方式
- 面向对象的方式
- 函数式 递归与链式 例: Jquery 链式编程
- 比如: 给 div 标签添加样式
$( ‘div‘ ).css( ‘border‘, ‘1px solid red‘ ) .css( ‘width‘, ‘400px‘ ) .css( ‘height‘, ‘200px‘ );
面向对象的概念
对象的定义:无序属性的集合,其属性可以包含基本值,对象或是函数
- 面向:将脸朝向... -> 关注对象,用对象
- 面向过程 -> 使用过程的方式开发
- 关注过程,步骤,细节,顺序。 事无巨细,亲自为之
- 面向对象开发 -> 使用对象的方式开发
- 要做什么,找到对象,告诉他做,等结果
- 面向对象不是面向过程的替代,是面向过程的封装,可以理解为面向对象编程就是面向编程的一种简化
万物皆对象
- 在实际开发中,对象是一个抽象的概念,可以简单理解为: 数据集或功能集。可以混合使用
- 数据集: 很多数据打包到一起。 { name: ‘张三‘, age:19, gender:‘男‘ }
- 假设展示 10 个商品数据,每个商品有名字,描述,价格,图片等
- 对象可以用来保存数据,每一个商品可以变成对象 { name: ‘123‘, desc:‘123‘, price: 0 }
- 引入数组,将多个对象数据存储在数组中(数组也是对象)
- 功能集(函数集,方法集)
- 在 js 中,所谓的对象就是 键值对 的集合
- 数据集: 很多数据打包到一起。 { name: ‘张三‘, age:19, gender:‘男‘ }
-
给页面中所有的div和p添加边框,设置宽高
<body> <!-- 给页面中所有的div和p添加边框,设置宽高 --> <div>div1</div> <p>p标签</p> <div>div2</div> </body> <script> /* 获得所有div */ var divs = document.getElementsByTagName(‘div‘); var ps = document.getElementsByTagName(‘p‘); /* 设置样式 */ /* 由于 getby 获取的是 伪数组 */ for ( var i = 0; i < divs.length; i++ ) { divs[ i ].style.border = ‘1px solid red‘; divs[ i ].style.width = ‘300px‘; divs[ i ].style.height = ‘200px‘; } for ( var i = 0; i < ps.length; i++ ) { ps[ i ].style.border = ‘1px solid blue‘; ps[ i ].style.width = ‘300px‘; ps[ i ].style.height = ‘200px‘; } </script>
-
利用函数封装较长的功能
<script> /* 利用函数封装较长的功能 */ function tag ( tagName ) { return document.getElementsByTagName( tagName ); } var divs = tag(‘div‘); var ps = tag(‘p‘); for ( var i = 0; i < divs.length; i++ ) { divs[i].style.border = ‘1px solid red‘; divs[i].style.width = ‘300px‘; divs[i].style.height = ‘200px‘; } for ( var i = 0; i < ps.length; i++ ) { ps[i].style.border = ‘1px solid blue‘; ps[i].style.width = ‘300px‘; ps[i].style.height = ‘200px‘; } <script>
-
封装函数进行循环
<script> function tag ( tagName ) { return document.getElementsByTagName( tagName ); } function addCss( array, border, width, height ) { for( var i = 0; i < array.length; i++ ) { array[i].style.border = border; array[i].style.width = width; array[i].style.height = height; } } var divs = tag( ‘div‘ ); var ps = tag(‘p‘); addCss( divs, ‘1px solid red‘, ‘400px‘, ‘50px‘ ); addCss( ps, ‘1px solid blue‘, ‘300px‘, ‘50px‘ ); </script>
-
addCss的改良
<script> function tag ( tagName ) { return document.getElementsByTagName( tagName ); } function addCss( array, styles ) { for( var i = 0; i < array.length; i++ ) { for( var k in styles ) { array[i].style[k] = styles[k]; } } } var divs = tag(‘div‘); var ps = tag(‘p‘); addCss( divs, { ‘border‘: ‘1px solid red‘, ‘width‘: ‘400px‘, ‘height‘: ‘50px‘ }); addCss( ps, { ‘border‘: ‘1px solid red‘, ‘width‘: ‘400px‘, ‘height‘: ‘50px‘ }); </script>
- 自己定义的函数越多,那么开发的时候就越方便,但是,也有隐患,自己定义的越多,那么与引入的框架出现冲突的几率就越大,一旦出现名字冲突了,就会造成框架中的功能无法使用。
- 怎么办? 定义的名字越多,问题的几率越大,最简单的方法就是尽可能少定义名字
- 定义一个对象,然后所有的函数,变成这个对象的方法即可
<script> var jespon = { tag: function( tagName ) { return document.getElementsByTagName( tagName ); }, addCss: function( array, styles ) { for( var i = 0; i < array.length; i++ ) { for( var k in styles ) { array[i].style[k] = styles[k]; } } } } var divs = jespon.tag(‘div‘); var ps = jespon.tag(‘p‘); jespon.addCss( divs, { ‘border‘: ‘1px solid red‘, ‘width‘: ‘400px‘, ‘height‘: ‘50px‘, ‘background‘: ‘green‘ }); jespon.addCss( ps, { ‘border‘: ‘1px solid red‘, ‘width‘: ‘400px‘, ‘height‘: ‘50px‘ }); </script>
面向对象的特性
- 抽象性:抽取我们所需要的数据信息等
- 封装性
- 继承性
- (多态性)
名词提炼法找对象
- 做一个表格排序
- 面向过程: 1创建表格, 2添加点击事件, 3排序,更新数据
- 面向对象: 1创建表格对象, 2添加数据
实际开发的时候如果需要完成一个功能
- 首先考虑系统是否提供了对象
- 例如: 创建图片: var img = new Image(); img.src = ‘...png‘;
- 例如: 获取页面元素:document 标签对象
- 用 document对象 获取导航栏里面的所有li 标签 var nav = document.getElementById( ‘nav‘ ); var lis = document.getElementsByTagName( ‘li‘ );
- 如果系统没有提供,可以自己定义,或第三方
<script> var jespon = { tag: function( tagName ) { return document.getElementsByTagName( tagName ); }, addCss: function( array, styles ) { for( var i = 0; i < array.length; i++ ) { for( var k in styles ) { array[i].style[k] = styles[k]; } } } attr: ..., getId: ... } <script>
js 的数据类型
- 基本数据类型(值类型):数字 number,字符串 string,布尔 boolean
- 基本数据类型的存储模型就是一个方格里面放一个数据
- 复合数据类型(引用类型):对象(数组,时间类型,函数类型)
- 复合类型,除了函数其他的数据类型 无法使用 typeof 来获得数据类型名,typeof arr 等 拿到的都是object
- 需要使用 Object.prototype.toString.apply( )
- 空类型: null undefined
var arr = [1, 2, 3]; console.log( typeof arr ); //object console.log( Object.prototype.toString.apply(arr) ); // [object Array]
复合类型的存储模型
- 复合类型的对象是一个单独的内存区域, 对象有什么属性, 那么内存区域中就有什么数据. 变量 p 只存储该对象的 ‘地址‘. 所以 p 不是真正存储数据的区域.
// 联想内存逻辑图 var arr1 = [ 1, 2, 3, 4 ]; var arr2 = [ { name: ‘张三‘, age: 19, gender: ‘男‘ }, { name: ‘李四‘, age: 18, gender: ‘男‘ }, { name: ‘小李‘, age: 17, gender: ‘女‘ } ];
值类型和引用类型的存储特征
- 值类型的数据,只需要开辟一段内存存储数据即可
var a = 123; var b = ‘abc‘; var c = true;
- 对象类型(引用类型),对象才是真正的数据,需要占据单独的内存。而变量名只是存储着对象的内存地址(引用)
- 即创建一个对象,并赋值,需要两块内存空间,一个存储数据(对象)。另一个存储变量以引用对象
- var o = { name: "张三", age: 19 },前后各占一块空间,前者于栈,后者于堆
值类型与引用类型的赋值与传参的特性
-
赋值:将原变量中的数据拷贝一份,然后存储到给定变量中
-
值类型
var a = 123; // 有个盒子a,里面存了123 var b ; // 有个盒子 b, 里面什么都没有 (undenfied) b = a; // 将 a 中存储的东西赋值一份,然后赋值为 b,即存储在 b 中
- b 和 a 是两个独立的变量, 两者之间不再有关系。
- 改变其中一个数据,另一个不变。
-
引用类型
var o1 = { num:123 }; var o2; // 赋值 o2 = o1; //o1 中存储的是引用,或‘地址’
- 将 o1 中存储的内容拷贝一份,存储到 o2 中,o1 和 o2 虽然是不相同的两个变量, 即两个独立的盒子. 但是由于拷贝的内容是地址,存储的地址相同。
- 在访问数据的时候, o1 与 o2 也是访问同一个数据, o1 将数据修改了, o2 再读取,读取的就是修改后的数据。
-
函数参数传递
-
什么是函数参数传递 函数要调用,一般会给函数传递参数 在调用函数的时候,会将参数中表示的数据拷贝一份,然后给参数赋值
-
值类型传递
function foo ( num ) { console.log( ‘num:‘ + num ); // 123 num++; console.log( ‘num:‘ + num ); // 124 } // 调用 var a = 123; console.log( a ); // 123 foo( a ); // 调用就是执行,将 a 中存的值,拷贝一份 // 然后进入 函数 foo // 给参数赋值,相当于 num = a; // 进入函数体,开始执行函数 console.log( a ); // 123
-
引用类型传递
function foo ( num ) { console.log( ‘nu====m:‘ + num[ 0 ] ); // 123 num[ 0 ]++; console.log( ‘num:‘ + num[ 0 ] ); // 124 } // 调用 var a = [ 123 ]; console.log( a[ 0 ] ); // 123 foo( a ); console.log( a[ 0 ] ); // 124
此时的赋值特性与前面介绍的值类型引用类型的赋值是一个特点
深拷贝与浅拷贝
什么是拷贝: 就是创建一个与目标数据一模一样的数据
var p = { name: ‘张三‘ };
var p1 = p; // 是否存在拷贝
// 一般描述拷贝是指拷贝对象
p1 = {};
p1.name = p.name;// 才是拷贝
给 对象 p 提供一个 clone 方法, 完成拷贝
- 浅拷贝:如果对象的属性也是一个引用类型, 拷贝的时候不重新创建一个新的对象来实现该属性的拷贝, 那么就是浅拷贝.即任何不完全的拷贝都是浅拷贝
- 深拷贝:将两个对象完全从内存中隔离开, 就是深拷贝. 即每一个引用属性, 以及引用属性的引用属性, ... 全部拷贝出来.
构造函数( 构造器 constructor )的作用
构造器:用来创建对象的函数。 js 中对象的动态特性, 即 想要什么属性就可以给什么属性
var o = {}; // 这时 o 对象没有 name 属性
o.name = "aaa"; // 这时 o 对象拥有了 name 属性且值为 “aaa”
在 js 中 对象如果没有指定的属性, 只需要利用赋值就 可以给对象 动态 提供该属性.
-
点语法与关联数组语法
o.name = ‘jim‘; // 点语法赋值 console.log( o.name ); // 点语法取值 o[ ‘name‘ ] = ‘tom‘; // 关联数组语法赋值 console.log( o[ ‘name‘ ] ); // 关联数组语法取值
-
创建一个 Person 对象
var p = {}; // 什么都没有的对象 // 根据需要添加成员 p.name = ‘张三‘; p.age = 30; p.gender = ‘男‘;
-
简化,提供一个创建 Person 对象的函数
function createPerson( name, age, gender ) { var p = {}; p.name = name; p.age = age; p.gender = gender; return p; } var p1 = createPerson( ‘jepson‘, 19, ‘男‘ ); var p2 = createPerson( ‘lucy‘, 18, ‘女‘ );
这个( 这种类型 )的函数就是用来创建对象的, 即生产对象. 常常将这类函数, 称为 ‘工厂函数‘。
构造方法创建对象
构造器中不需要 return 语句. 一般也可以不写 调用构造器的时候, 使用 new 运算符引导 在构造器中 this 表示当前对象. 给对象提供成员使用 this.xxx 的 方式
- 将 createPerson 改造成构造器
function createPerson( name, age, gender ) { this.name = name; this.age = age; this.gender = gender; } // 调用构造器创建对象 var p = new createPerson( ‘jepson‘, 19, ‘男‘ );
- 构造器创建对象的本质: 还是使用对象的动态特性 -> 首先执行 new 运算符. 即创建对象. 可以简单看做为 {} 的简写, var p = new ... ‘相当于‘ var p = {} -> 调用构造器. 并隐含一个参数, 即刚刚创建的对象. -> 在构造器中使用 this 引用刚刚创建出来的对象. -> 构造器结束是 默认返回 this
- 补充说明 -> 构造器的名字, 一般使用 Pascal 命名规则( 首字母大写的 ) -> 一般为了与其他面向对象的编程语言( C++, C#, Java )保持一致. 称构造函数名为类名
function Person( name, age, gender ) { this.name = name; this.age = age; this.gender = gender; } // 调用构造器创建对象 var p = new Person( ‘jepson‘, 19, ‘男‘ );
异常与捕获
- 异常:简单的说, 就是代码在执行过程中出现的错误. 并不是代码的语法错误。一旦出现异常, 其后的代码, 不再执行。
-
try catch 语法 1) try-catch 形态
try { 代码 } catch ( e ) { 代码 }
2) try-catch-finally 形态,后台用的比较多一点,主要用于释放资源,js 不是很常用
// 例如: 将页面中第一个 a 标签的 href 设置值,但是没有 这个标签时,会出错 try { var list = document.getElementsByTagName( ‘a‘ ); list[ 0 ].href = ‘123‘; console.log( 2 ); } catch ( e ) { console.log( ‘e: ‘ + e ); // e: TypeError: Cannot set property ‘href‘ of undefined console.log( 3 ); } finally { console.log( 5 ); // 无论是否出现异常, try 语法结束的时候都要执行 finally 中的代码 } console.log( 4 );
-
自定义抛出异常 一般可以封装函数完成特定的功能
try { var age = 15; if ( age < 18 ) { throw { ‘info‘: "未满十八岁" }; } console.log(‘已满十八岁‘); } catch ( e ) { console.log( e ); // { ‘info‘: "未满十八岁" } console.log( e.info ); // "未满十八岁" }
-
抛出异常的语法 throw 对象 throw { name:‘jepson‘, age:18 }
以上是关于面向对象笔记一的主要内容,如果未能解决你的问题,请参考以下文章