面向对象
面向对象的概念
- 所谓面向对象就用抽象方式创建基于显示世界模型的一种变成模式,面向对象编程可以看做是使用一系列对象互相协作的软件设计
- 备注: 面向对象全称"Object Oriented Programming"简称"OOP"
- 面向对象编程的主要三个特征是:
-
封装 - 所谓封装就是按要求使用得到对象的结果.
- 相关数据(用于存储属性)
- 基于这些数据所能做的事情
- 继承 - 继承通常是指类与类之间的关系,如果两个类都有相同的属性或方法,那么可以让一个类继承另一个类这样就不需要在前者再次定义同样的属性或方法
- 多态 - 不同的对象可以定义具有相同名称的方法,方法是作用于所在的对象中.这种不同对象通过相同方法的调用实现各自行为的能力,被称为多态
构造函数
- 构造函数又称为构造器,是对象中的一个方法,在实例化时构造器被调用.在JavaScript中函数就可以作为构造器使用,所以就不用特意定义一个构造器方法
- 语法: 创建构造函数(类的概念) - 用于创建对象(属性和方法)function 构造函数名称(){ this.属性名 = 属性值;this.方法名 = function(){ 方法体}}
- 注意: this关键字 -> 指代利用当前构造函数创建的对象
示例代码:
function Hero(name){ this.name = name; this.sayMe = function(){ console.log('我是' + name); }}// 利用构造函数创建对象var hero = new Hero('张无忌');console.log(hero);// 调用结果为 Hero { name: '张无忌', sayMe: [Function] }var obj = { name : '张无忌', sayMe : function(){ console.log('我是张无忌'); }};console.log(obj);// 调用结果为 { name: '张无忌', sayMe: [Function: sayMe] }
控制台调用结果对比图:
函数与构造函数
示例代码:
// 1.函数;2.构造函数function Hero(name){ var v = 100;// 局部变量 function n(){}// 内部函数 this.name = name;// 属性 this.sayMe = function(){// 属性 console.log('我是'+name); }}// 1.函数调用Hero();// 2.构造函数使用var hero = new Hero();function fun(){ var v = 100;// 局部变量 // 方法 this.get = function(){ return v; } this.set = function(value){ v = value; }}// 构造函数var f = new fun();console.log(f);// 调用结果为 fun { get: [Function], set: [Function] }console.log(f.get());// 调用结果为 100f.set(200);console.log(f.get());// 调用结果为 200
获取属性描述符
-
通过定义对象(属性或方法)这种方式
- 属性默认都是数据描述符
- 语法: 使用Object.getOwnPropertyDescriptor()方法获取指定属性的描述符 Object.getOwnPropertyDescriptor(obj,prop) obj - 表示指定属性对应的目标对象 prop - 表示获取描述符的目标属性名称 返回值 - 其属性描述符对象
示例代码:
var obj = { name : '张无忌'}var result = Object.getOwnPropertyDescriptor(obj,'name');console.log(result);
控制台效果图:
设置属性描述符
-
Object.defineProperty()方法为对象定义新属性或修改现有属性,并返回该对象
-
Object.defineProperty(obj,prop,descriptor)
- obj - 要在其上定义属性的对象
- prop - 要定义或修改的属性的名称
- descriptor - 将被定义或修改的属性描述符
- 返回值 - 被传递给函数的对象
-
-
Object.defineProperties()方法为对象定义一个或多个新属性或修改现有属性,并返回该对象
-
Object.defineProperties(obj,props)
- obj - 要在其上定义属性的对象
- props - 要定义其可枚举属性或修改的属性描述符的对象
- 返回值 - 被传递给函数的对象
-
示例代码:
var obj = { // 定义对象的同时定义了该属性以及值(可修改、可删除以及可枚举的) name : '张无忌'}/* Object.defineProperty(obj, prop, desc)方法 * 作用 * 用于定义目标对象的新属性 * 用于修改目标对象的已存在属性 * 参数 * obj - 表示目标对象 * prop - 表示目标对象的目标属性名称 * desc - 表示属性描述符,必须是对象格式 { value : 值 } * 返回值 - 返回传递的对象 */Object.defineProperty(obj, 'name', { value : '周芷若'});console.log(obj.name);// 周芷若/* 同样都是为对象新增属性 1.如果直接使用 "对象名.属性名 = 值" -> 可修改、可删除以及可枚举的 2.如果使用Object.defineProperty()方法新增属性 * 该新属性是不可修改、不可删除以及不可枚举的 */Object.defineProperty(obj, 'age', { value : 18});console.log(obj.age);// 18var result1 = Object.getOwnPropertyDescriptor(obj, 'age');console.log(result1);// 一旦属性的值是不可修改的 - 如果执行修改操作时 -> 没有语法报错,但是无效obj.age = 80;console.log(obj.age);// 18obj.job = '教主';var result2 = Object.getOwnPropertyDescriptor(obj, 'job');console.log(result2);
属性描述符的可选键值 - 设置属性描述符writable
- writable - Boolean值,表示目标属性的值是否可以被修改
- 当且仅当该属性的writable为true时,value才能被赋值运算符改变
- 备注: 默认为false
示例代码:
var obj = { // 定义对象的同时定义了该属性以及值(可修改、可删除以及可枚举的) name : '张无忌'}// 修改现有属性Object.defineProperty(obj, 'name', { value : '周芷若', writable : false // 不可修改});console.log(obj.name);// 周芷若// 修改name属性值obj.name = '赵敏';console.log(obj.name);// 周芷若Object.defineProperty(obj, 'age', { value : 18, writable : true});console.log(obj.age);// 18// 修改age属性值obj.age = 80;console.log(obj.age);// 80// 删除age属性值delete obj.age;console.log(obj.age);// undefined
属性描述符的可选键值 - 设置属性描述符configurable
- configurable - Boolean值,表示目标属性的描述符是否可以被修改
- 当且仅当该属性的configurable为true时, 该属性描述符才能够被改变同时该属性也能从对应的对象上被删除
- 备注: 默认为false
示例代码:
var obj = { // 定义对象的同时定义了该属性以及值(可修改、可删除以及可枚举的) name : '张无忌'}// 修改现有属性Object.defineProperty(obj, 'name', { value : '周芷若', writable : true, // 控制当前属性是否可被修改 configurable : true // 控制当前属性是否可被删除});console.log(obj.name);// 周芷若// 修改name属性值obj.name = '赵敏';console.log(obj.name);// 周芷若// 删除name属性值delete obj.name;console.log(obj.name);// 周芷若
属性描述符的可选键值 - 设置属性描述符enumerable
- enumerable - Boolean值,表示目标属性是否可遍历.
- 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中
- 备注: 默认为false
示例代码:
var obj = { // 定义对象的同时定义了该属性以及值(可修改、可删除以及可枚举的) name : '张无忌'}Object.defineProperty(obj, 'name', { value : '周芷若', enumerable : false});console.log(obj.name);// 周芷若/* 属性描述符enumerable - 控制当前属性是否可被枚举(遍历) * 仅能循环遍历对象中可被枚举的属性 * for...in语句 * keys()方法 * 可以循环遍历对象中可被枚举和不可被枚举的属性 * getOwnPropertyNames()方法 */for (var i in obj) { console.log(i);}var result1 = Object.keys(obj);console.log(result1);var result2 = Object.getOwnPropertyNames(obj);console.log(result2);
属性描述符存取器
- 对象的属性除了可以直接定义以外,还可以使用存取器进行定义.
- 其中setter为存值函数 - 使用属性面舒服中的set;
- getter为取值函数 - 使用属性描述符中的get
示例代码:
var obj = { name : '张无忌'}var value;// 全局变量Object.defineProperty(obj, 'name', { // 获取指定的属性值 get : function(){// 当获取或访问当前属性时,会调用get方法 console.log('this is get function'); /* 类似于数据描述符中的value * get方法在被调用时,不能传递任何参数 * get方法在被调用时,允许传递this关键字 * this - 表示当前的目标对象(不能调用对象的当前目标属性) */ return value;// 由于变量为初始化,调用时可能结果为 undefined }, /* set方法用于定义当前目标属性的修改作用 * 该方法接收唯一的一个参数 -> 作为当前目标属性的新的值 * 通过属性修改操作指定的新的值 -> 作为形参对应的实参 */ set : function(newValue){ console.log('this is set function: ' + value); /* set方法在被调用时,允许传递this关键字 * this - 表示当前的目标对象(不能调用对象的当前目标属性) */ value = newValue; }});console.log(obj.name);// undefinedobj.name = '赵敏';console.log(obj.name);// 赵敏
控制台调用图效果:
- 注意: 如果方法被调用时用this关键字时要加一个全局变量配合否则控制台会报错
控制台调用图效果:
属性描述符存取器的另一种方法
示例代码:
var value;var obj = { // 存取描述符中的get get attr() {// 表示当前目标属性名称 return value; }, // 存取描述符中的set set attr(newValue) {// 表示当前目标属性名称 console.log('setter: ' + newValue); value = newValue; }}console.log(obj.attr);//调用结果为 "undefined"obj.attr = 100;//调用结果为 "setter: 100"
控制台调用图效果:
防篡改对象
- 所谓防篡改对象就是不让篡改对象的属性或方法
- 防篡改对象的属性或方法提供了三种保护方式:
- 禁止扩展 - 就是禁止为对象扩展的属性或方法
- 密封对象 - 就是禁止扩展新的属性或方法,禁止配置现有的属性或方法的描述符,仅允许读写的属性值(就是只能有不能改)
- 冻结对象 - 就是禁止对象执行执行任何修改操作
禁止扩展
-
如果禁止为对象扩展新的属性或方法,需要修改对象属性的extensible为false
- Object.preventExtensions()方法用于设置指定对象不可扩展,即不能新增属性或方法
- Object.isExtensible()方法判断一个对象是否可扩展的(就是是否可以在它上面添加新的属性)
示例代码:
var obj = {};// 将对象设置禁止扩展Object.preventExtensions(obj);// 新增属性或方法无效 -> 语法没有报错obj.name = '张无忌';console.log(obj);/* Object.defineProperty()方法新增属性 * 结果 - 报错 * 信息 - TypeError: Cannot define property:name, object is not extensible. */Object.defineProperty(obj, 'name', { value : '周芷若'});console.log(obj);/* Object.isExtensible(obj)方法 * 作用 - 用于判断指定目标对象是否可扩展 * 返回值 * true - 表示指定目标对象是可扩展的 * false - 表示指定目标哦对象是不可扩展的 */var result = Object.isExtensible(obj);console.log(result);
密封对象
-
密封对象,就是指禁止为对象扩展新的属性或方法,并且禁止修改现有属性的描述符
- Object.seal()方法用于封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置.当前属性的值只要可写就可以改变
- Object.isSealed()方法判断一个对象是否被密封
示例代码:
var obj = { name : '张无忌' // 表示可修改};console.log(Object.getOwnPropertyDescriptor(obj, 'name'));/* 将该对象进行密封 1.不能为该对象新增属性或方法 2.不能修改该对象的属性或方法的描述符 * configurable * enumerable */Object.seal(obj);console.log(Object.getOwnPropertyDescriptor(obj, 'name'));/* 新增属性obj.age = 18;console.log(obj);// 修改属性obj.name = '周芷若';console.log(obj);*//*Object.defineProperty(obj, 'age', { value : 18});*/Object.defineProperty(obj, 'name', { value : '周芷若', writable : false, // 表示不可修改 configurable : true, enumerable : false});console.log(Object.getOwnPropertyDescriptor(obj, 'name'))console.log(obj);obj.name = '赵敏';console.log(obj);
冻结对象
-
冻结对象,就是指禁止对对象执行任何操作
- Object.freeze()方法用于冻结一个对象,冻结指的是不能像这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性以及不能修改该对象已有属性的可枚举性,可配置性,可写性.该方法返回被冻结的对象
- Object.isFrozen()方法判断一个对象是否被冻结
示例代码:
var obj = { name : '张无忌'}// 冻结对象Object.freeze(obj);/*obj.age = 18;console.log(obj);obj.name = '周芷若';console.log(obj);delete obj.name;console.log(obj);*/Object.defineProperty(obj, 'age', { value : 18});console.log(obj);