面向对象
面向对象的概述
面向对象的特征
- 封装性
- 继承性
- 多态性
自定义对象
var o1={}
var o2={name:'Jim'}
var o3={name:'a',age:19,gender:'男'}
var o4={
name:'xsw',
age:20,
gender:'男'
sayHello:function(){
console.log('hi')
}
}
JSON数据格式:
JSON实际上是一个字符串 需要使用双引号包裹对象的成员名和字符串的值
{"name":"xsw","age":20,"gender":"男"}
var obj={"name":"xsw","age":20,"gender":"男"}
JSON不仅可以用来保存对象 还可以保存数字字符串 数组等其他类型的数据
访问对象成员
<script>
let o5={}
o5.name="xsw"
o5.age=20
o5.introduce=function (){
alert('My name is'+this.name+'age:'+o5.age) //this 代表当前对象
}
document.write(o5.introduce())
</script>
JavaScript允许在代码执行时动态的给对象增加成员
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试访问对象</title>
</head>
<body>
<input id="k" type="text" value="xsw"/>
<input id="v" type="text" value="最帅的男人"/>
<input id="btn" type="button" value="test">
</body>
<script>
var k =document.getElementById('k')
var v =document.getElementById('v')
var btn = document.getElementById('btn')
var o={}
btn.onclick=function (){
o[k.value]=v.value;
alert(o) //最后输出结果 Object (xsw:"最帅的男人")
}
</script>
</html>
对象成员遍历
var obj ={name:"xsw","age":20}
for (var k in obj){
console.log(k+'--'+obj[k])
}
多学一招:
当需要判断一个对象中的某个成员是否存在是 可以使用 in 运算符
var obj2={name:"Tom",age:20} //如果存在 输出true 反之输出false
console.log('name' in obj2)
console.log('gender' in obj2)
深拷贝与浅拷贝
拷贝(copy)是指将一个目标数据复制一份 形成两个个体
构造函数
构造函数时Javascript创建对象的另外一种方式 相对于字面量 ’{}‘ 的方式 构造函数可以创建出一些具有相同特征的对象
JavaScript内置的构造函数
JavaScript提供了 Object String Number 等构造函数 通过 new() 构造函数名() 即可创建对象
let obj = new Object() //新建Object对象
let str = new String('123') //新建String 对象
console.log(obj.constructor) //constructor查看对象是由哪个函数创建的
console.log(str.constructor)
console.log({}.constructor)
自定义构造函数
定义的注意事项:
- 构造函数的命名推荐采用帕斯卡命名规则 即所有的单词首字母大写
- 在构造函数内部 使用this来表示刚刚创建的对象
function Person(name,age){
this.name=name;
this.age=age;
this.sayHello = function (){
alert('Hi My name is'+this.name)
}
}
let p1 = new Person("辛思伟",21)
let p2 = new Person("黄梦茹",20)
console.log(p1)
console.log(p2)
p1.sayHello()
console.log(p1.constructor)
//ES6 添加了 class 方法
class Person2{
constructor(name,age,gender) {
this.name=name
this.age=age
this.gender=gender
}
introduce(){
alert('My name is'+this.name+'age is'+this.age+'gender:'+this.gender)
}
}
let p3 = new Person2('黄梦茹',20,"女")
console.log(p3)
p3.introduce()
私有成员
在构造函数中使用var关键字定于的变量成为私有成员 在实例对象后无法通过 “对象成员” 的方式进行 访问 但是私有成员可以在对象的成员方法中访问
构造函数中的return关键字:
由于构造函数也是函数 因此构造函数中也可以使用return关键字 但是在使用时与普通函数有一定的区别 若使用return返回一个数组或对象等引用类型数据 则构造函数会直接返回该数据 而不会返回原来创建的对象 如果返回的是基本类型的数据 则返回的数据无效 依然会返回原来创建的对象
函数中的this指向
分析this指向:
- 使用new关键字将函数作为构造函数调用时 构造函数内部的this指向新创建的对象
- 直接通过函数名调用函数时 this指向的是全局对象(在浏览器中表示window对象)
- 如果将函数作为对象的方法调用 this将会指向该对象
内置对象
String对象
String对象对象的常用属性和方法:
var str="HelloWorld!"
console.log(str.length)
console.log(str.charAt('5'))
console.log(str.indexOf('l'))
console.log(str.lastIndexOf('l'))
console.log(str.substring(0,[5]))
console.log(str.substr(0,[5]))
console.log(str.toLowerCase()) //获取字符串的小写形式
console.log(str.toUpperCase()) //获取字符串的大写形式
console.log(str.split('1'))
console.log(str.split('1',3))
console.log(str.replace('Hello','JavaScript'))
Number对象
Number对象用于处理整数 浮点数
常用的属性:
let num=12345.6789
console.log(num.toFixed())
console.log(num.toFixed(1))
console.log(num.toFixed(6))
console.log(Number.MAX_VALUE)
console.log(Number.MIN_VALUE)
Math对象
Math对象用于对数值进行数学运算 与其他对象不同的是 该对象不是一个构造函数 不需要实例化就能使用
let n = 10.88
console.log(Math.ceil(n))
console.log(Math.abs(n)) //绝对值
console.log(Math.PI)
console.log(Math.round(n))
console.log(Math.random())
console.log(Math.max(1,2,3,4))
console.log(Math.min(1,2,3,4))
//利用random可以生成任何范围的随机数 公式为:Math.random()*(n-m)+m
let t =Math.random()*(37-36)+36
console.log(t.toFixed(1))
Date对象
Date对象用于处理日期和时间
let date = new Date()
document.write(date.toString()+'<br>') //中国标准时间
document.write(date.getFullYear()+'<br>')
document.write(date.getMonth()+'<br>') //获取月份 0表示一月 1表示二月 以此类推
document.write(date.getDate()+'<br>')
document.write(date.getHours()+'<br>')
document.write(date.getMinutes()+'<br>')
document.write()
let date2 = new Date(2000,4,16,5,20,13)
document.write(date2.toString())
制作日历
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>年历</title>
<style type="text/css">
body{text-align:center;}
.box{margin:0 auto;width:880px;}
.title{background: #ff0000;}
table{height:200px;width:200px;font-size:12px;text-align:center;float:left;margin:10px;font-family:arial;}
</style>
<script src="calendar.js">
</script>
<script>
var year = parseInt(prompt("请输入一个年份:"))
document.write(calendar(year))
</script>
</head>
<body>
</body>
</html>
//定义年历生成函数
function calendar(y) {
//获取指定年份1月1日的星期数值
let w = new Date(y, 0).getDay()
let html = '<div class="box">'
//拼接每个月份的表格
for (let m = 1; m <= 12; ++m) {
html += '<table>'
html += '<tr class="title"><th colspan="7">' + y + '年' + m + '月</th></tr>'
html += '<tr><td>日</td><td>一</td><td>二</td><td>三</td><td>四</td>'
html += '<td>五</td><td>六</td></tr>'
//获取月份m共有多少天
let max = new Date(y, m, 0).getDate()
html += '<tr>' //开始<tr>标签
for (d = 1; d <= max; ++d) {
if (w && d == 1) { //如果该月的第一天不是星期日 则填充空白
html += '<td colspan="' + w + '"></td>'
}
html += '<td>' + d + '</td>'
if (w == 6 && d != max) { //如果星期六不是该月的最后一天 则换行
html += '</tr><tr>'
} else if (d == max) { //该月的最后一天 闭合<tr>标签
html += '</tr>'
}
w = (w + 1 > 6) ? 0 : w + 1
}
html += '</table>'
}
html+='</div>'
return html
}
错误处理与代码调试
错误处理
let o ={}
try {
o.func()
}catch (e){
console.log(e)
}
console.log('test')
错误对象
在发生错误时 错误出现的位置 错误的类型 错误信息等数据 都会被封装起来 以一个对象的形式传递给
catch语句 通过catch(e) 的方式 来接收 e-----可以看作是错误对象的实例
错误类型
原型与继承
原型
例如:
利用原型可以提高代码的复用性 假设有 p1和p2两个对象 都是构造函数Person创建 然后顶一个introduce方法则 p1 p2两个对象都有了introduce方法 但是这种方式存在了一种缺点 就是每个基于Person创建的对象都会重复的保存这些完全相同的方法 带来不必要的浪费
function Person(name){
this.name=name
this.intoduce=function(){}
}
let p1 = new Person('x')
let p2 = new Person('s')
console.log(p1.intoduce==p2.intoduce) //输出结果 为 false
原型对象的使用方法
在JavaScript中 每定义一个函数 就随之有一个对象存在 函数通过 prototype属性指向该对象 这个对象称之为原型对象 简称原型
function Person(name){
console.log(typeof Person.prototype)
}
Person()
继承
利用原型对象实现继承
原型对象是JavaScript实现继承的传统方式 如果一个对象中本来没有某个属性或方法 但是可以从另一个对象中获得 就实现了继承
function person(name){
this.name=name;
person.prototype.sayHello=function (){
console.log("Hi My name is"+this.name)
}
}
let p1 = new person('辛思伟');
let p2 = new person('黄梦茹');
p1.sayHello();
p2.sayHello();
替换原型对象实现继承
function person(){
person.prototype.sayHello=function (){
console.log('原来的对象')
}
}
let p1 = new person();
person.prototype={
sayHello:function (){
console.log('我是新对象')
}
}
let p2 = new person()
p1.sayHello();
p2.sayHello();
静态成员
静态成员指室友构造函数所使用的成员 与之相对的是由构造函数创建的对象所使用的实例成员
原型链
对象的构造函数 :
再原型对象中 存在一个constructor属性 指向该对象的构造函数
function person(){}
person.prototype.constructor==person //返回true
基于person 构造函数创建的实例对象 原本没有constrouctor属性 但因为连接到了person函数的原型对象
就可以访问到constructor属性
function person(){}
new person().constructor ==person //返回true
因此通过constructor属性 即可查询该对象的构造函数
对象的原型对象
由于对象可以通过constructor属性访问构造函数 构造函数可以通过prototype属性访问原型对象 因此使用
对象.constructor.prototype 的方式即可访问对象的原型对象
function person(){}
new person().constructor.prototype ==person.prototype //返回true
函数的构造函数:
由于函数本质上就是对象 所以函数也有构造函数 再 JavaScript中 自定义函数以及 String Object等内置构造函数都是 function函数
而 function 函数的构造函数是 function本身 通过toString 方法可以查看函数的信息
function person(){}
person.constructor.toString() //返回结果function Function(){[nativecode]}
person.constructor == Function; //返回true
String.constructor == Function; //返回true
Object.constructor == Function; //返回true
Number.constructor == Function; //返回true
Function.constructor == Function; //返回true
原型链的结构
- 自定义函数 以及 String Object Number等内置函数 都是由 function 函数创建的 function函数是由 function函数自身创建的
- 每个构造函数都有一个原型对象 构造函数通过 prototype属性指向原型对象 原型对象通过 constructor属性指向构造函数
- 由构造函数创建的实例对象 继承自构造函数的原型对象 通过实例对象的 proto 属性可以直接访问原型对象
- 构造函数的原型对象 继承自 Object的原型对象 而 Object的原型对象的 proto属性为 null