在计算机编程中,对象是一种非常重要的概念。它可以帮助我们更好地组织和管理数据,使代码更加模块化和可复用。对象可以存储多个键值对,每个键值对表示一个属性,属性可以是基本类型的值或者其他对象。通过对象,我们可以定义和调用方法,对属性进行操作或者实现特定的功能。
面向对象编程的思想强调通过对象和类来组织和管理代码,使其更加易于理解和维护。实际上,将问题和解决方案分解为对象是一种非常自然和直观的方式,也是实现代码复用和模块化的关键。
在接下来的学习中,我们将更加深入地认识和掌握这些概念,并通过小案例来实践和巩固所学的知识。让我们一起展开学习之旅吧!
语法: k和v之间用冒号分隔,每组k:v之间用逗号分隔,最后一个k:v对后可以不书写逗号
'favorite-book':'舒克和贝塔'
属性名中有短横,不符合]S标识符命名规范,属性名必须用引号包裹对象属性的访问
可以用“点语法”访问对象中指定键的值
xiaoming.name;//小明
xiaoming.age;//12
xiaoming.hobbys;//['足球',游泳','编程]
如果属性名不符合]S标识符命名规范,则必须用方括号的写
法来访问
xiaoming['favorite-book'];//舒克和贝塔
如果属性名以变量形式存储,则必须使用方括号形式
var obj = {
a:1,
b:2,
C:3
};
//属性名用变量存储
var key ='b';
console.log(obj.key); //undefined
console.log(obj[key]);//2
属性的更改
var obj ={
a:10
}
obj.a = 30; //将obj里a的值改成了30
ob].a++; // a = 31
属性的创建
var obj ={
a:10
};
obj.b = 40; //在obj对象中创建了b:40这个键值对
属性的删除
如果要删除某个对象的属性,需要使用delete操作符
var obj = {
a:1,
b:2
};
delete obj.a;
如果某个属性值是函数,则它也被称为对象的"方法"
varxiaoming = {
sayHello:function(){ //sayHello方法
console.log('你好,我是小明,今年12岁,我是个男生');
}
}
用点方法调用函数xiaoming.sayHello();
方法也是函数,只不过方法是对象的"函数属性",它需要用对象打点调用
var obj1 = obj2
这样的语法克隆一个对象和数组的类型相似,对象的深克隆需要使用递归
var obj1 = {
a:1,
b:2,
c:[33,44,{
m:55,
n:66,
p:[77,88]
}]
};
// 定义一个深克隆函数
function deepClone(o){
// 判断o是对象还是数组,必须先判断是不是数组,因为数组的类型也是对象
if(Array.isArray(o)){
//数组
var result = [];
for(var i=0;i < o.length;i++){
result.push(deepClone(o[i]));
}
}else if(typeof o == 'object'){
// 对象
var result = {};
for (var k in o){
result[k] = deepClone(o[k])
}
}else{
//基本类型值
var result = o;
}
return result;
}
var obj2 = deepClone(obj1);
console.log(obj2);
// 测试一下
console.log(obj1 === obj2); //false
obj1.c.push(99);
console.log(obj2); //obj2是不变的,因为没有'藕断丝连'的现象
函数的上下文(this关键字)由调用方式决定; 同一个函数,用不同的形式调用它,则函数的上下文不同
var xiaoming = {
nickname:小明,
age:12,
sayHello = function (){
console..log('我是'+this.nickname+',我'+this.age+'岁了);
}
};
情形1:对象打点调用函数,函数中的this指代这个打点的对象
xiaoming.sayHello();
情形2:圆括号直接调用函数,函数中的this指代window对象
var sayHello = xiaoming.sayHello;
sayHello();
function是“运行时上下文"策略
函数如果不调用,则不能确定函数的上下文
规则①
对象.方法();
规则②
函数();
规则③
数组[下标]();
规则④
IIFE中的函数,上下文是window对象
(function(){
})();
规则⑤
setInterval(函数,时间);
setTimeout(函数,时间);
规则⑥
DOM元素.onclick=function(){
}
函数.ca11(上下文);
要用逗号罗列参数函数.apply(上下文);
要把参数写到数组中进行“四步走”
Java、C++等是"面向对象”(object-oriented)语言
JavaScript是"基于对象”(object-based)语言
JavaScript中的构造函数可以类比于OO语言中的"类”,写法的确类似,但和真正OO语言还是有本质不同
console.log(xiaoming.__proto__ === People.prototype); //true
代码示例
function People(){
}
var xiaoming = new People();
console.log(xiaoming.__proto__.__proto__ === Object.prototype); //true
console.log(Object.prototype.__proto__); //null
console.log(Object.prototype.hasOwnProperty('hasOwnProperty')); //true
数组的原型链
var arr = [22,33,4,555];
console.log(arr.__proto__ === Array.prototype); //true
console.log(arr.__proto__ .__proto__=== Object.prototype); //true
console.log(Array.prototype.hasOwnProperty('push')); //true
继承描述了两个类之间的"is a kind of"关系,比如学生“是一种”人,所以人类和学生类之间就构成继承关系
People是"父类”(或"超类”、"基类”);Student是“子类”(或“派生类”)
子类丰富了父类,让类描述得更具体、更细化
举例
Student.prototype = new People();
//父类:人类
function People(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
People.prototype.sayHello = function (){
console.log('你好,我是'+this.name +'我今年'+this.age+'岁了');
}
People.prototype.sleep = function (){
console.log(this.nam+'开始睡觉,zzzz');
}
// 子类:学生
function Student(name,age,sex,school,studentNumber){
this.name = name;
this.age = age;
this.sex = sex;
this.school = school;
this.studentNumber = studentNumber;
}
//关键语句,实现继承
Student.prototype = new People();
Student.prototype.study = function (){
console.log(this.name + '正在学习');
}
Student.prototype.exam = function (){
console.log(this.name+'正在考试,加油!');
}
//实例化
var hanmeimei = new Student('韩梅梅',12,'女','CSDN大学',123456);
hanmeimei.study();
hanmeimei.sayHello();
使用面向对象编程,就能以"组件化"的思维解决大量红绿灯相互冲突的问题
面向对象编程,最重要的就是编写类
TrafficLight类
代码示例:
#box img{
width: 80px ;
}
<div id="box" >div>
//定义红绿灯类,构造函数
function TrafficLight(){
//颜色属性,一开始都是红色
//红色1,黄色2,绿色3
this.color = 1;
//调用自己的初始化方法
this.init();
//绑定监听
this.bindEvent();
}
//初始化方法
TrafficLight.prototype.init = function (){
// alert('我是init方法');
//创建自己的DOM
this.dom = document.createElement('img');
this.dom.src = this.color+'.jpg';
box.appendChild(this.dom);
}
// 绑定监听
TrafficLight.prototype.bindEvent = function (){
//备份上下文,这里的this指的是JS实例
var self = this;
//当自己的dom被点击时
this.dom.onclick = function (){
// 当被点击时,调用自己的changeColor方法
self.changeColor();
};
}
// 改变颜色
TrafficLight.prototype.changeColor = function (){
// 改变自己的color属性,从而有一种"自治"的感觉,自己管理自己不干扰别的红绿灯
this.color++;
if(this.color == 4){
this.color = 1;
}
// 光color属性变化没用,还要更改自己的dom中src属性,才能更换图片
this.dom.src = this.color+'.jpg';
};
// 得到盒子
var box = document.getElementById('box');
// 实例化100个
var count = 100;
// 当count-- 为0的时候,判断为false,跳出循环
while(count--){
new TrafficLight();
}
Boll类的方法
实现多个小球的动画
代码示例:
body{
background-color: black;
}
.ball{
position: absolute;
border-radius: 50%;
}
//小球类
function Ball(x,y){
//属性x,y表示的是圆心的坐标
this.x = x;
this.y = y;
//透明的
this.opacity = 1;
do{
// 这个小球的x增量和y的增量
this.dX = parseInt(Math.random()*20)-10;
this.dY = parseInt(Math.random()*20)-10;
}while(this.dX === 0 || this.dY === 0)
// 小球的背景颜色
this.color = colorArr[parseInt(Math.random()*colorArr.length)];
// 小球半径
this.r = 20;
// 初始化
this.init();
// 把自己推入数组,注意:这里的this不是类本身,而是实例
ballArr.push(this);
}
Ball.prototype.init = function (){
//创建自己的dom
this.dom = document.createElement('div');
this.dom.className = 'ball';
this.dom.style.width = this.r *2 +'px';
this.dom.style.height = this.r *2 +'px';
this.dom.style.left = this.x - this.r+'px';
this.dom.style.top = this.y - this.r+'px';
this.dom.style.backgroundColor = this.color;
//上树
document.body.appendChild(this.dom);
}
// 更新
Ball.prototype.update = function (){
// 位置改变
this.x += this.dX;
this.y -= this.dY;
// 半径改变
this.r += 0.2;
// 透明度改变
this.opacity -= 0.05;
this.dom.style.width = this.r *2 +'px';
this.dom.style.height = this.r *2 +'px';
this.dom.style.left = this.x - this.r+'px';
this.dom.style.top = this.y - this.r+'px';
this.dom.style.opacity = this.opacity;
// 当透明度小于0,就需要从数组中删除自己,DOM元素也要删除自己
if(this.opacity<0){
//从数组中删除自己
for (var i = 0; i<ballArr.length;i++){
if(ballArr[i] == this){
ballArr.splice(i,1);
}
//还要删除自己的dom
document.body.removeChild(this.dom);
}
}
};
// 把所有的小球实例都放到一个数组中
var ballArr = [];
// 初始颜色数组
var colorArr = ['#66CCCC','#CCFFCC','#FF99CC','#FF6666','#CC3399','#ff6600']
// 定时器,负责更新所有的小球实例
setInterval(function (){
//遍历数组 ,调用update方法
for(var i= 0;i<ballArr.length;i++){
ballArr[i].update();
}
},20);
// 鼠标指针的监听
document.onmousemove = function (e){
//得到鼠标指针的位置
var x = e.clientX;
var y = e.clientY;
new Ball(x,y);
}
幂和开方:Math.pow()、Math.sqrt()
向上取整和向下取整:Math.ceil()、Math.floor()
Math.round()方法: 四舍五入
Math.max(): 得到参数列表最大值
Math.max()要求参数必须是“罗列出来”,而不能是数组
用apply方法,它可以指定函数的上下文,并且以数组的形式传入“零散值”当做函数的参数
var arr = [3,6,9,2];
var max = Math.max.apply(null,arr);
console.log(max); // 9
Math.min(): 得到参数列表最小值
Math.random(): 得到0~1之间的小数
时间戳表示1970年1月1日零点整距离某时刻的毫秒数
通过getTime()方法或者Date.parse()函数可以将日期对象变为时间戳
通过new Date(时间戳)的写法,可以将时间戳变为日期对象
内置构造函数
内置构造函数的关系
借助构造函数(也被称为"伪造对象"或"经典继承")
function People(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
this.arr = [22,33,44];
}
function Student(name,sex,age,school,sid){
People.call(this,name,sex,age); // 借助构造函数
this.school = school;
this.sid = sid;
}
var xiaoming = new Student('小明','男',12,'CSDN学校',123455);
console.log(xiaoming);
</script>
组合继承(最常用)
//父类
function People(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
}
People.prototype.sayHello = function (){
console.log('你好,我是'+this.name+'今年'+this.age+'岁了');
}
People.prototype.sleep = function (){
console.log(this.name+'正在睡觉');
}
//子类
function Student(name,sex,age,school,sid){
//借助构造函数
People.call(this,name,sex,age);
this.school = school;
this.sid = sid;
}
//实现继承:借助原型链
Student.prototype = new People();
Student.prototype.exam = function (){
console.log(this.name + '正在考试')
}
Student.prototype.sayHello = function (){
console.log('敬礼!你好,我是'+this.name+'今年'+this.age+'岁了'+this.school+'的学生');
}
var xiaoming = new Student('小明','男',12,'CSDN学校',123455);
console.log(xiaoming);
xiaoming.sayHello();
xiaoming.sleep();
xiaoming.exam();
原型式继承
寄生式继承
寄生组合式继承
instanceof运算符