1、面向对象的概念
从编程思想角度解释:
面向过程的编程思想,关注的是解决问题的步骤,
面向对象的编程思想,关注的是解决问题需要的对象。
面向对象的编程思想继承于面向过程。
从编程语言的角度解释:
面向对象的编程语言,必须有‘类’和‘对象’这两个概念,并且对象是经由类创建出来的;还需要有‘继承’,‘封装’,‘多态’三个特征。
js语言不符合以上条件,但是有‘对象’的概念,所以他是一门基于对象的编程语言。
js和面向对象的关系:利用面向对象的编程思想来指导js代码的书写方式。
2、使用js创建对象的方法
1)字面量创建对象
优势:快捷、直观、方便
劣势:需要创建多个对象时,代码冗余
var per = {
name: 'xiaoWang',
age: 23,
sayHi: function () {
alert('hello');
}
};
// 访问对象的属性:
// 1.对象名+'.'+属性名
// 2.对象名+[]+属性名字符串
alert(per['name']);
per.sayHi()
2)工厂方法创建对象
工厂模式:通过调用工厂,给工厂传递参数,则工厂就能批量生产对应的产品
优势:解决了代码冗余的问题
劣势:无法区分该对象的类型(如:系统类型,如number是Number()创建的,但是自定义类型无法获取到)
// 定义创建对象的工厂
function creatPerson(name, age) {
// 1.创建空对象
var per = {};
// 2.给空对象添加属性和方法
per.name = name;
per.age = age;
per.sayHi = function () {
alert(name +'hello')
}
// 把创建的对象返回出去
return per;
}
var per1 = creatPerson('xiaoWang', 23);
console.log(per1);
// per1.sayHi();
console.log(per1 instanceof creatPerson);
var num = new Number();
// 可以通过instanceof方法判断实例的类型
console.log(num instanceof Number);
var num1 = 23;
console.log(num1 instanceof Number);
var per2 = creatPerson('xiaoXuan', 18);
console.log(per2);
per2.sayHi();
3)构造函数创建对象
优势:解决了获取对象类型的问题,使用构造函数创建的对象自带一个
constructor,通过该属性获取对象的类型(还可以使用instanceof检测对
象是那个类型的实例:(personinstanceof Person),返回1个布尔值 )
劣势:内存占用有点大
// 构造函数函数名首字母大写
function CreatePreson(name, age) {
// 把所有的属性和方法挂载在this指针上。将来this指向谁,这些属性和方法就添加在谁身上
this.name = name;
this.age = age;
this.sayHi = function () {
alert(this.name + 'hello');
};
}
// 调用构造函数创建对象
// new + 构造函数名
// new:通过new关键字调用的函数,new会首先在内存中开辟一块存储空间,然后把构造函数中的this指针指向这块存储空间,这样给this指针绑定的属性、方法,也就添加进了这块存储空间中。最后把存储空间的地址给per对象保存
// 通过构造函数创建出来的对象可以借助相关方法判断归属关系。
var per1 = new CreatePreson('xiaoXuan', 18);
var per2 = new CreatePreson('xiaoWang', 23);
per1.sayHi();
console.log(per1 instanceof CreatePreson);//true
console.log(per1.sayHi == per2.sayHi);//false
工厂模式和构造函数创建对象的区别:
1)构造函数没有显示的创建新对象
2)直接把属性和方法赋值给了this指针
3)构造函数没有return语句
4)使用构造函数穿建出来的对象可以标示这个对象属于哪一种类型
普通函数调用和构造函数调用的区别:
1)构造函数必须使用new操作符来创建新对象,如果像调用普通函数那样创建对象,就是在全局作用域中调用函数了,this指针会指向window对象。
3、如何使用对象
1)访问对象属性的两种方法:点语法和[]访问某一个属性
使用点语法访问属性,点后直接跟属性名
使[]访问属性,[]里是属性字符串(必须是字符串类型的数据)或保存
属性名字符串的变量
使用for...in...遍历对象的所有属性
for (var property in per1) {
console.log(property
+"="+ per1[property]);
}
3、继承
通过一个类(父类、父构造函数)创建出另一个类(子类、子构造函数),这样新创建出来的类不仅拥有了原有类的属性、方法、子类,而且也可以添加自己独有的属性、方法,子类也可以重写父类的方法。
1)通过call实现继承(借用构造函数实现继承)
function ClassA(name) {
this.name = name;
this.sayHi = function () {
alert("hello");
}
}
function ClassB(name) {
// call函数是Function下的1个方法,第1个参数表示要修改原函数中this指针的指向,第2个参数起,依次代表父构造器所需要的参数
ClassA.call(this, name);
// 添加新新法
this.sayBye = function () {
alert("bye-bye");
}
}
var cB = new ClassB("zhangsan");
cB.sayHi();
2)原型链实现继承
function Parent(name) {
this.name = name;
this.say = function () {
alert("hello");
}
}
function Child(age) {
this.age = age;
}
// 通过子类的原型指针,从父类继承相关的属性、⽅法:让子类的原型指针指向父类对象
Child.prototype = new Parent(‘张三’);
// 因为prototype中还包含1个constructor属性,这个属性用来指向prototype所在的构造函数,所以要把constructor指向的构造函数改回Child,保
证从该函数创建出的对象的constructor属性不会指向Parent
Child.prototype.constructor = Child;
var child = new Child(23);
alert(child.age);
child.say();
3)组合方式实现继承
实例属性使用CALL的方式继承,原型方法使用原型链方式继承
// 使用call/apply实现对实例属性的继承
// 使用原型实现对原型芳法的继承
function CreateAnimal(name, age) {
this.name = name;
this.age = age;
}
CreateAnimal.prototype.sayHi = function () {
alert('hello');
}
function CreatePerson(name, age, gender) {
CreateAnimal.call(this, name, age);
this.gender = gender;
}
CreatePerson.prototype = new CreateAnimal();
CreatePerson.prototype.constructor = CreatePerson;
CreatePerson.prototype.eatFoot = function () {
alert('吃饭了');
}
var per = new CreatePerson('zhengSAN', 18, 'MAN');
// console.log(per.gender);
per.sayHi();
per.eatFoot();
4)通过冒充调用方式实现继承
// 父类
function ClassA(sColor) {
this.color = sColor;
this.show = function () {
alert(this.color);
}
}
var cA = new ClassA("red");
cA.show();
// 子类
function ClassB(sColor,age) {
// 通过冒充实现子类继承父类的方法、属性
this.newFn = ClassA; // 给this添加1个新的函数,也就是ClassA这个构造函数
this.newFn(sColor); // 执⾏新添加进去的函数,通过this.newFn调⽤ClassA,进⽽修改了ClassA中this指针的指向
delete this.newFn; // 修改完指针的指向后,就可以把新添加的这个⽅法删掉(过河拆桥)
// 继续添加新属性\方法
this.age = age;
}
var cB = new ClassB("green", 23);
cB.show();
console.log(cB.age);
4、百度模板的使用
<!--定义模板 -->
<script id='news' type="text/template">
<!--<% %>:是百度模板的语法,如果需要在模板中植入逻辑代码,就需要使用这个符号包裹 -->
<h1> <%=title%> </h1>
<h3> <%=des%> </h3>
</script>
</body>
<script type="text/javascript">
// 调用模板
var data = {
title: "http://www.baidu.com",
des: "今天距离放假已不足二十四小时,好开心!!!"
}
var html0 = baidu.template('news', data);
console.log(html0);
// 把代码拼接进文档流
document.body.innerHTML = html0;
// document.appendChild(html0);
</script>
5、鼠标拖拽相关属性
window.onload = function () {
var div = document.querySelector('#div');
div.onclick = function (ev) {
// clientX\clientY坐标系原点是浏览器的左上角
// offsetX\offsetY坐标系原点是标签border以内的左上角
var e = ev || event;
// offsetLeft/offetTop:从html标签的左侧边框和顶部边框开始计算距离
// offsetWidth/offsetHeight包含了:边框、内边距、width/height
// console.log(div.offsetWidth);
console.log(ev);
}
}
鼠标拖拽相关事件
<style media="screen">
body {
height: 2000px;
}
#div {
width: 100px;
height: 100px;
background-color: hotpink;
position: absolute;
}
</style>
<script type="text/javascript">
window.onload = function () {
var div = document.querySelector('#div');
// 1、给标签添加鼠标按下
div.onmousedown = function (ev) {
var e = ev || event;
// 获取到鼠标坐标距离标签左侧和顶部的间隔
// 用鼠标移动后的位置-第一次点击时的位置,得出鼠标偏移的位置
// 把偏移的位置增加给div标签
var left = e.offsetX;
var top = e.offsetY;
document.onmousemove = function (ev) {
var e = ev || event;
console.log(e.offsetX);
var offsetLeft = e.pageX - div.offsetLeft - left;
var offsetTop = e.pageY - div.offsetTop - top;
div.style.left = div.offsetLeft + offsetLeft + 'px';
div.style.top = div.offsetTop + offsetTop + 'px';
}
div.onmouseup = function () {
// 把绑定在标签中的事件清理掉
document.onmousemove = null;
// this.onmousedown = null;
this.onmouseup = null;
}
}
}
</script>
</head>
<body>
<div id="div">
</div>
</body>