面向对象
1. 对象
一、对象简介
1、对象概念
对象属于一种复合的数据类型,在对象中可以保存多个数据类型的属性
2、对象分类
1)、内建对象: 由ES标准
中定义的对象,在任何ES环境中都可以使用
如 Math , String , Number, Boolean, Function
2)、宿主对象: 由js运行环境
提供的对象,目前主要指的是浏览器中提供的对象
如Bom,Dom分别是浏览器对象,文档对象。还有常见的对象 console.log
,Document
。
3)、自定义的对象:这个最难,因为其他的都已经规定好的了,主要学习的也是这个,由开发人员自主创建 。
二、创建对象
使用new
调用的函数是构造对象函数 construcor
构造函数时专门创建对象的函数。
格式:
var 对象变量名 = new Object() ;
实例:
var obj = new Object () ;
console.log( obj) ;
控制台输出:
{}[[Prototype]]: Object
分析: new Object()
表示创建一个对象( 注意Object的O是大写 ),给对象实例化一个变量obj。此时的对象只是一个空对象,变量没有实例化。
三、对象属性
1、基本概念
在对象中保存的值被称为属性
格式:
对象.属性名 = 属性值 ;
实例:
var obj.name = "孙悟空" ;
分析: 同样的,属性实质表示是具体内容,属性名就是变量是一个容器,而属性值才是真正的内容,相当于字面量。从面向对象角度来看,属性就是属性值的「抽象」,而属性值就是属性的「具体」。
2、读取属性
概念: 读取属性就是获取属性变量中的属性值。
格式:
对象.属性名
实例:
// 输出 孙悟空
console.log( obj.name ); // 孙悟空
分析: 使用「.」来访问对象的属性值。修改属性值 相当于重新给属性赋值。
3、删除属性
格式:
delete obj.name
实例:
var obj = new Object() ; // 使用new的对象都是大写开头
obj.name = "孙悟空" ;
console.log("删除前name: " + obj.name) ; // 删除前name: 孙悟空
delete obj.name
console.log("删除后name: " + obj.name) ; //删除后name: undefined
分析: delete obj.name
之前有属性名变量和属性值,使用delete后,没有这个obj的属性值,所以值为 undefined,但属性名变量存在。
4、属性变量的表示
为了表示属性(变量)有很多方式
对象的属性变量名不强制要求标识符命名
规则,但是如果需要使用特殊
的名字,不能采用 .
的方式访问属性值,需采用对象名["属性名"]
的方式。
格式:
var 对象变量名 = new Object() ;
// 访问 修改 属性值
对象变量名[属性名] = 新属性值 ;
实例:
var obj = new Object();
obj["名字"] = "孙悟空";
console.log(obj["名字"]); // 孙悟空
分析: 那么此时的名字
是属性名,而孙悟空
是属性值。
与默认使用的添加属性值的方法相比,这个方法 [ ]
中的属性名还可以是变量
,这样使用起来也更加灵活。js 对象的属性名
, 可以是任意数据类型
(包括对象)
四、IN运算符
作用: 可以检查某对象是否包含指定属性,如果有则返回true,否则返回flase。
格式:
属性 in 对象变量
实例:
//检查 obj 中是否含有 test1 属性
var obj = new Object();
obj["名字"] = "孙悟空";
console.log(obj["名字"]); // 孙悟空
console.log( "名字" in obj); // true
console.log( "年龄" in obj); // false
五、数据类型和引用类型区别
1、基本数据类型
基本数据类型的值直接保存在 栈内存
中,值与值之间是相互独立的,修改一个变量不会影响另一个变量。
var a = 123;
var b = a;
console.log("b的值: " + b); // b的值: 123
分析: a先赋值123,然后b赋值a的值。b的123和a的123没有任何关系,只是看起来值 相同,是相互独立的。
2、引用数据类型(对象)
var obj1 = new Object();
var obj2 = new Object();
obj1.name = "孙悟空" ;
obj2 = obj1;
console.log("obj1的name: " + obj1.name ) ; // obj1的name: 孙悟空
console.log("obj12的name: " + obj2.name ) ; // obj12的name: 孙悟空
// 修改 obj2的name
obj2.name = "猪八戒" ;
console.log("obj1的name: " + obj1.name ) ; // obj1的name: 猪八戒
console.log("obj12的name: " + obj2.name ) ; // obj12的name: 猪八戒
分析: 修改 obj2的name值,obj1的name也跟着改变了,原因是obj1和obj2在内存中指向的是同一块区域。
第一次创建obj1对象时,实际是开辟一个空间,将空间的地址0x99赋值给一个变量,作为对象变量obj1。当执行obj2 = obj1;
时,将变量obj1的值0x99 “传递” 给 obj2, 这样导致 obj1 和 obj2 指向同一块内存空间。当执行obj2.name = "猪八戒" ;
时,这个「猪八戒」实质赋值给了 0x99所指向的内存空间 的name变量,这样 obj1 和obj2指向的内存空间的name属性 值都是 「猪八戒」了。
3、 创建对象另一种方式
创建对象的另一种方式: 使用对象的字面量
创建对象。
格式:
// 使用 字面量方式创建 对象
var 属性变量 = {};
// 使用 new 创建对象
var 属性变量 = new Object();
实例:
// 创建
var obj1 = {} ;
// 创建并赋值
var obj2 = {name:"猪八戒"};
console.log("obj2的名字: " + obj2.name); // obj2的名字: 猪八戒
分析: 两种方式本质是一样的。但是使用对象的字面量
使用方便一些创建对象
的时候就可以给属性赋值
。若有多个属性则属性「名-值对」之间用 ,
号隔开。开发中常用 对象字面量
的方法 创建对象
2. 方法
1、方法概念
方法是站在面向对象的角度的“函数”。
2、使用方法
// 创建对象
var obj = new Object () ;
// 向对象添加属性
obj.name = "孙悟空";
obj.age = 18;
对象中的属性可以是任意的类型
,其中特殊的时对象,函数...。
obj.sayName = function ( ) {
console.log( obj.name );
};
此时对象的属性就是一个函数。使用函数对象(有名函数)方式的一个用处是为了 调用函数
格式:
对象.方法名();
实例:
obj.sayName( );
// 创建对象
var obj = new Object();
// 向对象添加属性 (基本类型)
obj.name = "孙悟空";
obj.age = 18;
// 向对象添加属性 (函数)
obj.sayName = function () {
console.log("name: " + obj.name);
};
// 使用方法
obj.sayName(); // name: 孙悟空
分析: 对象使用自己的方法sayName打印出 自己的属性name。这里的创建函数的形式是 变量式。
用普通的函数形式的调用函数 ,其实也有一个对象,这个对象就是
window
,当然上面例子的函数是赋值给一个对象的(实际上是给对象的属性🤣),那么这个函数对象就是这个obj啦。如果一个函数是一个对象的属性(像上例子一样),那么。那么把这个函数称为这个对象的方法( method )
3. 枚举对象中的属性
概念: 枚举对象就是用字面量形式创建对象,形式上是「名值对」,格式整齐,一枚一枚的。
// 用函数 字面量 创建 函数
var obj = {
name : "孙悟空",
age : 18,
gender : "男",
address : "花果山"
};
🚀T-测试遍历输出枚举对象的属性。
// 用函数 字面量 创建 函数
var obj = {
name: "孙悟空",
age: 18,
gender: "男",
address: "花果山",
};
// for 循环遍历输出枚举对象 属性
for(var n in obj) {
console.log(n);
}
控制台输出结果:
name
age
gender
address
分析: 这里使用for in
语句对“集合”形式的内容遍历。
🚀T-测试遍历输出枚举对象的属性值。
// 用函数 字面量 创建 函数
var obj = {
name: "孙悟空",
age: 18,
gender: "男",
address: "花果山",
};
// for 循环遍历输出枚举对象 属性
for(var n in obj) {
console.log(obj[n]);
}
控制台输出结果:
孙悟空
18
男
花果山
分析: for in
循环特点, n代表obj属性集合中的某个属性,是一个变量,每次一轮循环属性就变成下一个属性,使用obj[属性]
形式获取属性值。
window对象 由浏览器创建 在全局作用域中创建的方法,函数都可以是window对象的属性,方法。全局的函数会作为window的方法储存
4. 提前声明现象
1、变量声明提前
情况1: 先用var 定义变量a赋值,后使用console.log()打印a的值。
var a = 3;
console.log("a = " + a ); // a = 3
分析: 当按照先声明var
,再赋值的方式,没有错误
情况2: 调换上下语句。当var
声明变量放在调用此变量语句的后面,会出现奇怪效果。
console.log("a = " + a ); // a = undefined
var a = 3;
效果: 变量a没有出错,但是值为 undefined
。
分析:
情况3: 在情况2基础上去除var声明 ( 当不使用var
声明变量也放在使用变量语句的后面 )。
console.log("a = " + a ); // a = undefined
a = 3;
效果:
分析: 当变量声明的语句部分在变量使用语句的后面(下方)时,程序先执行有var的语句,但是不赋值,所以其情况2的值为 undefined。而情况3去掉var后,变量a就没有定义,声明,即a是非法的,就会出错。
理解: 可以理解为 编译器会先预处理,把 var
"浮"在上面。但变量要遵循先声明赋值,后使用的原则 (由上到下
)。
编译器没有"看到"var
,则执行变量的使用语句时,变量还未声明
,不认识,即报错。
2. 函数声明提前
和变量是一样的,大同小异
var a = 3;
var b = 4;
fun1();
function fun1(){
console.log("a = " + a);
}
fun2();
var fun2 = function(){
console.log("b = " + b);
}
效果:
(完)
5. 上下文对象this
6. 使用工厂方法创对象
1、工厂方法简介
概念: 工厂方法就是创建一个“模板”完成重复性,有个别参数不同的任务功能。
目的: 创建类
2、工厂方法创建
1)、不使用工厂方法创建对象( 字面量形式创建对象 )
var obj = {
name : "孙悟空",
age : 18,
gender : "男",
address : "花果山"
sayName : function( ) {
};
分析: 这样使用字面量形式创建对象,可以在创建的同时给属性复制,非常灵活。但这种方式也存在问题.就是当有大量创建对象的需求时,这种方式显得非常繁琐。而实际上这样的对象,属性类型和属性个数是基本固定的,变化也只是体现在具体属性值,也就是创建一个新的对象的过程只需要改变属性值。像这种有着重复结构,但是固定位置的内容不同可以考虑封装为函数,批量地处理,提升效率。
2)、使用工厂方法批量创建对象
function creartePerson(){
// 函数体
// 创建对象功能语句
// 返回对象
return obj;
}
creartePerson();
分析: 想实现这样的效果。使用creartePerson();
传递实参,在函数内部完成结构的建立和属性值的赋值。
完成函数体
function createPerson ( name ,age ,gender ,address ) {
var obj = new Object();
obj.name = name;
obj.age =age;
obj.gender = gender ;
obj.address =address;
obj.sayName = function () {
alert(this.name);
}
return obj;
};
createPerson(); //调用的时候可以传递不一样的参数值
这个createPerson
函数是创建对象的工厂
,obj是模板,模板也就是 类。
7. 构造函数
1、使用构造函数创建对象
使用:
// 创建模板
function Person(){ // 这个Person相当于一个这是一类事物
console.log(this);
}
// 创建对象psn
var psn = new Person(); //这个per相当于一个实例
控制台输出:
Person{}
_proto_:Object
分析: 此时的this 就是 psn
构造函数执行流程:
- 构造函数创新对象
- 新对象设为函数this
- 逐行执行代码
- 新建对象作返回值
所以之前的函数的构建中创建函数对象,用 new
这种方式其实是构造函数。
3、instanceof
概念: 使用 instanceof
可以判断一个对象是否是一个类的实例
// 创建构造方法
function Person(){
console.log(this);
}
// 创建对象
var psn = new Person();
// 判断psn是否属于 Person类
console.log(psn instanceof Person);
效果:
注意事项和细节:
- 构造函数首字母大写
- 普通函数直接调用
- 构造函数使用 New 关键字调用
- Object是所有的类的父类
4、构造函数修改
构造函数好是好,但是也存在一些问题。
构造函数中的方法是 每执行一次就要创建一个里面的新的方法,如果执行 10000次 ,也就是要创建10000个方法,关键是这些方法都是相同的。所以能不能利用这些一样的方法,使之称为共享的方法。
1)、使方法公共化: 将方法写入的到全局作用域中
- 将函数定义到全局作用域中的话,会污染全局作用域的空间。
- 不安全, 同一个函数名,容易被改写,覆盖。
8. 原型对象
引入一个概念原型
暂略...
9. toString() 方法
toSting( )是原型的方法 ,可以被对象重写
暂略...
10. 垃圾回收机制
将不适用的对象设为 null
暂略...
(完)