面向对象的三大特性
- 封装: 在JS中使用对象封装一些变量和函数
- 好处: 信息隐蔽, 方便扩展维护, 提高代码的复用性
- 继承: 一个类(对象)获取另一个类(对象)的属性和方法的一种形式
- 面向对象语言定义: 是否有类的概念(c++ Java)
- JS没有类的概念, JS从这个角度说不是面向对象语言. 但面向对象具有继承特性, 可以说JS支持面向对象语言
- 多态: 同一操作, 作用于不同对象, 会产生不同行为(解释)
- 实现: JS天生就具有多态的特性(弱类型语言)
创建对象的方式
-
字面量的方式
var student = { name: 'zs', age: 16, class: '一分钟精通JS' } //一个班级有N个学生, 通过字面量形式, 需要创建N个学生对象 //问题: 创建多个同类型的对象时, 大量代码冗余(重复代码) //价值: 只需要创建简单的几个对象
-
内置的构造函数
-
系统内置的构造函数: Object | Array | Math | Date | Function | String | Number | Boolean
var stu = new Object(); stu.name= 'zs'; stu.age= 16; stu.class= '一分钟精通JS'; //跟字面量的方式差不多, 问题也是一样-->创建对象的相同部分进行函数封装(简单工厂)
-
-
简单的工厂方式: 类似函数封装, 相同的不变, 不同的作为参数传进来
function person(){ var stu = new Object(); stu.name= 'zs'; stu.age= 16; stu.class= '一分钟精通JS'; //返回该对象 return stu; } var stu1 = person(); var stu2 = person(); //问题: 两个学生信息都一样 //优化如下: 不同的信息当做参数传进来 function person(name, age, classes){ var stu = new Object(); stu.name= name; stu.age= age; stu.class= classes; return stu; } function dog(name, age, classes){ var dog = new Object(); dog.name= name; dog.age= age; dog.class= classes; return dog; } var stu3 = person('zs', 16, '一分钟精通JS' ); var dog = dog('wangCai', 5 , '骑单车'); console.log(stu3 == dog); //false //问题: 创建不同类型的对象时, 无法分辨其类型
-
自定义构造函数-参照上一章构造函数创建对象
-
定义
- 自己定义的构造函数(首字母大写)-通过this设置属性/方法-使用new调用构造函数创建对象
-
执行过程
- 通过new关键字调用构造函数,构造函数内部默认创建一个新对象
- 将这个新对象赋值给this
- 通过this设置属性和方法
- 默认返回新创建对象
-
返回值
- 如果没有显示return, 默认返回构造函数内部新创建的对象
- 若写了返回值, 要看具体情况
- 如果返回值类型的数据, 就直接忽略, 返回内部新创建的对象
- 若返回引用类型的数据, 直接返回该数据(会覆盖内部新创建的对象)
-
自定义构造函数(区别于简单的工厂函数)
- 函数名首字母大写
- 自定义构造函数内部会默认创建一个对象-默认将这个对象赋值给this
- 默认会返回新创建的对象
- 创建不同类型的对象时, 可以分辨其类型
-
构造函数注意事项
- 函数传值: 函数当做参数传进构造函数
- 判断对象的类型
-
对象 instanceof 构造函数
: 判断指定对象是否由某个构造函数创建出来
-
- 获取对象类型: 构造器属性
obj.constructor
- 构造函数调用-区别于函数调用
new
关键字: 默认创建/返回对象-
构造函数: 对这个对象进行一些初始化的操作(将创建对象赋值给this, 通过this绑定属性/方法)
function Person(name) { // this = obj; console.log(this); this.name = name; // return obj; } var p1 = new Person('zs'); // 构造函数也是一个函数 var p2 = Person('ls'); // 可以这样写,但是不建议这样做 console.log(p2); // undefined, 直接调用构造函数,this指向window //分析打印结果 <script> function fn(){ var t = 1; this.x = 3; document.write(t); document.write(this.x); } var obj = new fn(); document.write(obj.x); document.write(fn()); </script>
构造函数的原型对象
-
原型对象定义
-
在构造函数创建出来时, 系统默认会创建一个对象与这个构造函数相关联, 这个对象称为该构造函数的原型对象
-
-
作用
- 使用构造函数创建出来的对象, 默认就可以使用该构造函数原型对象的属性和方法
访问原型对象:
构造函数.prototype
-
设置原型对象:
构造函数.prototype.name = 'name1';
- 原型对象本质也是一个对象, 可以利用对象的动态特性设置原型对象
-
约定
- 该对象构造函数的原型对象
- 构造函数的原型对象(原型) | 对象的原型对象(原型)
实例与实例化
- 实例: 通过构造函数创建出来的对象.
- 一般说: XX是构造函数的实例
- 实例成员: 实例属性+实例方法
- 实例化: 通过构造函数创建对象的过程
- 注意点
- 实例对象可以访问实例成员和原型成员, 但是不能够访问静态成员
- 构造函数在访问静态方法时, 内部的this指向的是构造函数自己, 不能访问到实例对象的成员
function Person() {
this.name = "张三"; //实例属性
var age = 18; //私有变量
this.showName = function () { //实例方法
console.log(this.name);
}
this.showAge = function () { //特权方法
console.log(age);
}
}
Person.prototype.show = function () { //原型方法
console.log(this.name);
}
Person.des = function () { //静态方法
console.log(this.name);
}
var p1 = new Person();
p1.showName(); //张三
p1.showAge(); //18
p1.show(); //张三
//p1.des(); //undefined ? 报错(Y)
Person.des(); //undefined ? 报错 ? 张三 ?Person(Y)
原型的使用方法
- 利用对象的动态特性设置原型对象
- 提供一个构造函数
- 设置原型对象的成员(原型属性+原型方法)
- 添加成员:
构造函数.prototype.name = "name1";
- 修改成员:
构造函数.prototype.name = "name2";
- 删除成员:
delete 构造函数.prototype.name;
- 添加成员:
- 替换原型对象: 自己定义的对象赋值给原型对象
- 替换原型对象之前创建的对象和替换之后创建的对象,他们的原型对象不是同一个对象
* 注意点: 获取替换原型对象的属性与替换之前原型对象的属性值不相等 * 建议: 最好在替换原型对象之后, 再创建对象
- 修正构造器属性
使用原型对象的注意事项
- 访问原型对象的属性-方式
-
对象.属性
(就近原则)- 首先查找自身是否有该属性, 若有就直接使用
- 若没有就查找该对象原型对象的属性, 若有就直接使用
- 再没有就返回
undefined
或报错
构造函数.prototype.属性
-
- 设置原型对象
- 通过
对象.属性
设置属性- 如果有这个属性就是修改, 没有这个属性就是添加属性, 不会修改原型对象的属性
- 设置原型对象的属性
- 通过
构造函数.prototype.属性
或者替换原型 - 如果原型属性是引用类型的数据, 可以通过
对象.属性.属性
的方式修改
- 通过
- 通过
构造器属性相关
-
constructor
属性: 指向与之对应的构造函数 -
对象.constructor
: 访问的是原型对象的constructor
属性
__proto__
属性
- 定义
- 构造函数创建出来的对象, 默认就有一个
__proto__
属性, 该属性指向该对象对应的构造函数的原型对象
- 构造函数创建出来的对象, 默认就有一个
- 访问原型对象-方式
构造函数.prototype
-
对象.__proto__
-
注意点: 在正式开发中, 不建议使用. 该属性不是ES标准, 是部分浏览器厂商方便调试程序
-
hasOwnProperty()
- 语法:
对象.hasOwnProperty("属性名")
- 定义: 判断对象中是否存在指定的属性(实例属性)/ES5 中判断对象的自有属性(hasOwnProperty)
- 与
in
区别:in
判断对象中是否存在指定的属性(不区分实例属性/原型属性)
isPrototypeOf()
- 语法:
构造函数.protoType.isPrototypeOf(对象)
- 定义: 判断一个对象是否是指定对象的原型对象(判断原型对象是否在整条原型链上)
- 与
instanceof
区别:instanceof
判断一个对象是否是指定构造函数的实例对象