导图社区 面向对象编程
这是一篇关于面向对象编程的思维导图,主要内容包括:改变this指向,this指针变量,构造函数里面的this,对象的继承,构造函数与特殊属性结合,特殊需求属性,构造函数与普通函数的区别,使用构造函数创建对象(超级重点!!!),对象的定义。
编辑于2024-09-30 10:26:36这是一篇关于JavaScript函数的思维导图,主要内容包括:回调函数,1.arguments实参数组,立即执行函数,闭包函数(超级重点),十、变量作用域,九、递归函数,八、返回值(重点),七、函数的重载,六、形参和实参,五、函数中的参数,四、函数调用,三、函数的其他声明方式(函数表达式),二、函数的作用,一、函数的定义。
这是一篇关于面向对象编程的思维导图,主要内容包括:改变this指向,this指针变量,构造函数里面的this,对象的继承,构造函数与特殊属性结合,特殊需求属性,构造函数与普通函数的区别,使用构造函数创建对象(超级重点!!!),对象的定义。
这是一篇关于JavaScript的思维导图,主要内容包括:数据类型检测,JavaScript的弱类型机制,学习前的注意事项,JavaScript数据类型,BOM:Boswer Object Model 浏览器对象模型,DOM:Document Object Model 文档对象模型,ECMAScript :JavaScript的语法。
社区模板帮助中心,点此进入>>
这是一篇关于JavaScript函数的思维导图,主要内容包括:回调函数,1.arguments实参数组,立即执行函数,闭包函数(超级重点),十、变量作用域,九、递归函数,八、返回值(重点),七、函数的重载,六、形参和实参,五、函数中的参数,四、函数调用,三、函数的其他声明方式(函数表达式),二、函数的作用,一、函数的定义。
这是一篇关于面向对象编程的思维导图,主要内容包括:改变this指向,this指针变量,构造函数里面的this,对象的继承,构造函数与特殊属性结合,特殊需求属性,构造函数与普通函数的区别,使用构造函数创建对象(超级重点!!!),对象的定义。
这是一篇关于JavaScript的思维导图,主要内容包括:数据类型检测,JavaScript的弱类型机制,学习前的注意事项,JavaScript数据类型,BOM:Boswer Object Model 浏览器对象模型,DOM:Document Object Model 文档对象模型,ECMAScript :JavaScript的语法。
面向对象编程
对象的定义
对象的创建我们可以理解成对象的封装
通过键值对创建对象
var 对象名 = { key1:value1, key2:value2, key3:function(){ } }
var stu_xm = { name:"小明", age:20, sex:"男", hobby:["打游戏","睡觉"], sayHello:function(){ console.log("hello"); } } 代码分析: 以上我们创建了一个对象叫做stu_xm,里面包含了name,age,sex,hobby,sayHello,5个属性,其中4个记录当前对象的特征,同时sayHello包含了一个方法描述了该对象的一种行为 以上方式创建的对象,我们也可以叫字面量对象
如果想再对象内部的方法中调用自己对象内部的属性,我们使用this变量,这个变量,现在先简单理解成,写在哪个对象里面,这个this就指向哪个对象 var stu_xm = { name:"小明", age:20, sex:"男", hobby:["打游戏","睡觉"], sayHello:function(){ console.log(this.name + "hello"); } }
通过Object方法创建
var obj = new Object(); //这种情况下的对象是空对象,我们需要手动去给它添加属性
添加或者删除对象内的属性
var obj = new Object(); obj.age = 20; obj.height = 180; 当我们调用了一个对象内不存在的属性时,就相当于是给这个对象添加一个属性 delete obj.age; //把obj对象中的age属性删除掉
使用构造函数创建对象(超级重点!!!)
function Student(_name,_age,_sex){ this.name = _name; this.age = _age; this.sex = _sex; this.sayHello = function(){ console.log("大家好,我叫" + this.name); } } var stu1 = new Student("张三",18,"男"); var stu2 = new Student("李四",20,"女"); 以上就是通过构造函数作为模板,实例化对象的过程
function createStudent(_name,_age,_sex){ var obj = { name:_name, age:_age, sex:_sex, sayHello:function(){ console.log("大家好,我叫" + this.name); } } return obj; } var stu3 = createStudent("王五",22,"女"); 代码分析: 以上写法其实就是模仿了new关键字调用函数的特性,直接通过普通返回对象的方式模拟了new调用构造函数的作用,但是这写法无法确定原型
构造函数与普通函数的区别
构造函数和普通函数在书写上没有区别,关键在于调用上
1、构造函数使用new调用,普通函数直接使用函数名() 调用
2、构造函数的返回值一定是一个对象,而普通函数的返回值根据return决定
3、普通函数的this它指向一个叫做window的对象,而构造函数的this指向的是创建的对象
4、如果通过new的形式调用构造函数,在执行的时候,如果没有实参需要传入可以不写调用时的小括号
5、构造函数的函数名首字母大写,普通函数的函数名我们使用小驼峰方式命名
特殊需求属性
Object.defineProperty() 定义对象属性
var stu1 = {}; Object.defineProperty(stu1,"name",{ //关于特殊需求属性的定义 }) 现在我们在对象stu1当中定义了一个name属性,现在它还是一个普通属性,现在我们来看下,我们可以设置属性的哪些行为描述
数据属性
数据属性就是一个包含一个数据的属性,我们可以在这个位置写入或者读取值,它有4个描述具体行为的特征
Configurable:表示是否可以让delete关键字删除这个属性,它的默认值是true
Enumerable:表示能否被for...in语句遍历到,这个默认值是true
writable:表示是否允许修改这个属性,默认是true
value:包含了这个属性的数据值,默认是undefined
var stu = { aaa:"hello" } //我们开始添加一个具备特殊行为描述的数据属性 Object.defineProperty(stu,"name",{ configurable:false, //表示不能被delete删除 enumerable:false, //表示不能被for...in循环遍历到 writable:false, //不能修改值 value:"小芳" }) for(var i in stu){ console.log(i); } 代码分析: 现在我们给stu对象添加了一个name属性,对这个属性各种行为都设置了false,表示这个属性既不能被删除,也不能被修改,还不能被遍历到(像一些关键参数,我们就需要做这样的行为描述,避免被误修改)
访问器属性
访问器只能通过Object.defineProperty() 方法定义
Configurable:表示是否可以让delete关键字删除这个属性,它的默认值是true
Enumerable:表示能否被for...in语句遍历到,这个默认值是true
Get:在读取属性的时候调用的函数,默认值是undefined
Set:在写入属性的时候调用的函数,默认值undefined
//现在有一个学生对象,我们在这个对象里面添加了一个数据属性birthday生日 //现在我们希望再添加一个年龄age属性,但是这个age属性的值要根据生日来计算 Object.defineProperty(stu,"age",{ configurable:false, //表示不能被delete删除 enumerable:true, //表示不能被for...in循环遍历到 get : function(){ return "你正在读取age的属性" }, set : function(v){ //v表示你赋的值 console.log("你正在对这个age属性赋值,你要赋值的是" + v); } }) 上面的get和set所定义的age属性就是一个访问器属性,它在取值和赋值的时候会分别触发get和set方法
访问器属性的具体作用: //现在有一个学生对象,我们在这个对象里面添加了一个数据属性birthday生日 //现在我们希望再添加一个年龄age属性,但是这个age属性的值要根据生日来计算 Object.defineProperty(stu,"age",{ configurable:false, //表示不能被delete删除 enumerable:true, //表示不能被for...in循环遍历到 get : function(){ var currentDate = new Date(); //获取当前时间点的日期对象 var birthdayDate = new Date(this.birthday); //获取出生日期的日期对象 var totalTime = currentDate.getTime() - birthdayDate.getTime(); var yearCount = parseInt(totalTime / 1000 / 60 / 60 / 24/ 365); return yearCount } // set:function(v){ // //v表示你赋的值 // console.log("你正在对这个age属性赋值,你要赋值的是" + v); // } }) 代码分析: 我们给stu对象添加了一个访问器属性age,并对age调用时的行为进行了描述, 对age属性的调用执行了一个get方法
针对访问器属性的调用和赋值操作
调用:执行访问器属性中行为描述的get方法
赋值:执行访问器属性中行为描述的set方法
Object.defineProperties() 定义对象属性
这个方法其实就是defineProperty的复数形式,可以一次定义多个带特殊行为描述的属性
获取对象特殊属性的描述信息
var nameDesc = Object.getOwnPropertyDesciptor(stu,"name"); //获取name属性的行为描述信息
构造函数与特殊属性结合
构造函数与特殊属性的结合,主要指的就是构造函数与Object.defineProperties的结合,这里我们就可以在构造函数的体内直接定义特殊属性,通过这个构造new出来的对象(对象的实例化)属性就一直是一个经过特殊定义的属性
案例: 现在我们定义一个Person构造函数,这个构造函数实例化的对象有5个属性,分别是name,birthday,sex,age,IDCard,这个5个属性不能被delete,同时都是只读,age属性根据生日计算,sex属性根据身份证号决定function Person(_name,_birthday,_IDCard){ Object.defineProperties(this,{ name:{ configurable:false, writable:false, value:_name }, birthday:{ configurable:false, writable:false, value:_birthday }, sex:{ configurable:false, get:function(){ return this.IDCard[16] % 2 == 0 ? "女" : "男" } }, age:{ configurable:false, get:function(){ var cTime = new Date(); var bTime = new Date(this.birthday); var total = cTime.getTime() - bTime.getTime(); return parseInt(total / 1000 / 60 / 60 / 24 / 365); } }, IDCard:{ configurable:false, writable:false, value:_IDCard } }) } var p1 = new Person("张三","2000-1-1","420111200001010222"); 代码分析: 以上代码中,我们首先创建了一个Person构造函数(模板),然后我们摒弃了之前的普通属性,改用defineProperties来设置特殊属性,让我们的构造函数new出来的对象所具备属性,更加牢固
对象的继承
现在我们通过控制台打印一个new出来的对象,在对象中找到一个属性 __proto__这个是对象的一个特殊属性,它指向的是对象的原型,我们可以把对象的原型理解成对象的父级
通过原型来实现继承: function Person(_height){ this.height = _height; this.sayHello = function(){ console.log("大家好") } } function Student(_userName,_sex,_age,_height){ this.userName = _userName; this.age = _age; this.sex = _sex; this.__proto__ = new Person(_height); } var s1 = new Student("张三","男",18,190); 代码分析: 这里我们通过对象的原型来实现了继承,对象的原型是在对象的一个叫做__proto__ 的属性中,而对象的原型我们可以认作对象的父级,所以当我们给这个属性赋值一个对象的时候,我们就认为一个对象具备了我们自己指定的父级,从而形成了父子关系,而父子关系的形成就意味着继承关系的形成,所以我们可以在new出来的对象中调用父级的属性和方法
改变this指向
函数的不同调用形式决定了this的指向
简单回顾下函数的调用方式
1.方法名()
2.var 方法名 = function(){}()
3.!function(){}()
4.new function(){}
另外三种调用形式,这三种方式也可以改变this指向
通过call方法调用
var name = "张三"; function sayHello(str){ console.log(str); console.log(this.name); } var stu1 = { name:"李四" } var stu2 = { name:"王五" } sayHello("普通调用") //window sayHello.call(stu1,"我是通过call来调用的");
通过apply来调用
这个调用方式与call一模一样,唯一不同在于原来方法的参数上面var name = "张三"; function sayHello(str,x,y,z){ console.log(str); console.log(x); console.log(this.name); } var stu1 = { name:"李四" } var stu2 = { name:"王五" } sayHello("普通调用") //window sayHello.apply(stu2,["我是apply调用的",1,2,3])
通过bind来调用
bind方法在调用方法的时候,不会立即执行原来的方法,而是返回一个新方法,通过新方法调用原方法var name = "张三"; function abc(){ console.log(this.name) } var stu1 = { name:"李四" } var x = abc.bind(stu1); x();
如果带有参数 var name = "张三"; function abc(x,y){ console.log(arguments); console.log(this.name,x,y) } var stu1 = { name:"李四" } var a = abc.bind(stu1,99,100); a(); var b = abc.bind(stu1,200); b(); var c = abc.bind(stu1); c(500,600) var d = abc.bind(stu1,60,70); d(80,90);
构造函数里面的this
我们在构造函数里面也使用了this,它指向谁? var name = "haha"; function Person(){ console.log(this.name); }
构造函数与普通函数在本质上没有任何区别,关键在于其调用方式,用new调用的函数我们就叫做构造函数
Person() //window.Person(),所以这里的this指向window new Person() //构造函数在调用的时候,体内的this指向的是当前实例化的对象
this指针变量
对象中的this
var name = "张三"; var stu = { name:"李四", sayHello:function(){ console.log(this.name); //stu.name } } 上面的代码中,我们看到sayHello方法里面有个this,那么这个this指向谁? 记住:this指向当前调用它的对象
问题:这个当前对象到底是谁? 1、在全局环境下,this指向的当前对象是window 2、在自己定义的对象当中,this指向当前调用这个方法的对象
关于window对象 之前我们在声明变量的时候通过var关键字声明变量,其实还可以理解成是window对象添加属性,通过function关键字声明的函数,其实就是给window对象添加方法,而直接添加在window对象下的属性和方法在调用的时候可以不写window对象自己
var name = "张三"; var stu = { name:"李四", sayHello:function(){ console.log(this.name); //stu.name } } var s = stu.sayHello; //调出stu对象中的sayHello方法体赋值给变量s // s(){ // console.log(this.name); // } window.s(); 代码分析: var s = stu.sayHello 相当于 window.s = stu.sayHello 所以接下来调 用s() 其实就是window.s() 根据之前讲过的,对象方法里面的this指向调用这个方法的对象,现在这个方法被window对象调用,所以里面的this就指向window
9-27