面向对象编程(OOP)
意义:使用对象时,只关注对象提供的功能,不关注其内部细节
一、创建对象
(1)、字面量创建对象
<!-- //字面量方式创建对象 -->
<script>
var obj = {
sex: '男', //添加属性 属性值(描述)
name: '东东',
//添加方法 行为
buy: function() {
console.log('吃饭');
}
}
console.log(obj);
console.log(obj.name); //东东
console.log(obj['sex']); //男
obj.buy(); //吃饭
</script>
(2)、new关键字,实例创建对象
-
缺点:造成代码冗余
<!-- 实例创建对象,(代码冗余) -->
<script>
var obj = new Object();
//1、添加属性
obj.name = '华子';
obj.gender = '男';
obj.play = function() {
console.log('打篮球');
}
console.log(obj.name); //华子
console.log(obj.gender); //男
obj.play() //打篮球
</script>
(3)、工厂模式创建对象
-
缺点:结构不明确
-
工厂函数:在函数内部常见对象,且用return出来给外部使用
-
好处:外部不需要关注工厂函数里面具体是怎么实现的(隐藏细节)
<script>
function factory(name, age) {
//1、创建对象
var obj = new Object();
//2、添加属性及方法
obj.myname = name;
obj.myage = age;
obj.skill = function () {
console.log('敲代码');
}
//3、返回创建好的对象
return obj;
}
console.log(factory('东东', 14));
console.log(factory('rose', 18));
</script>
(4)、构造函数创建对象
-
构造函数创建类(对象)
-
在构造函数中只要是this点出来的属性和方法都是公开的(public)
-
在构造函数内不使用this,用普通的函数创建和变量创建的就是私有的
-
私有的方法和变量,都只能在构造函数内部使用,并且和外部没有关系(在外部仍然可以继续使用)
<script>
function Animal(type, name, age, sex) {
this.myType = type;
this.myName = name;
this.myAge = age;
this.mySex = sex;
//私有的方法,虽然是写在animal里面,但是它是属于window的,本质上和anima对象无关
//私有的方法,只能在animal里面使用
var mySize = '2米';
function introduce() {
console.log('我身高' + mySize);
}
this.eat = function(food) {
console.log(this.myName + '吃' + food);
}
this.sleep = function() {
//私有方法
introduce()
console.log('睡觉');
}
}
//创建一个animal类的实例
//在构造函数中,只要是用this点出来的属性和方法就都是public的【公开的】
var tiger = new Animal('爬行', '狮子', 11, '公');
console.log(tiger.myName);
tiger.eat('玉米');
tiger.sleep() //我睡觉和2米
//在外部又创建了一个公开的属性,也叫mySize
tiger.mySize = '3米';
console.log(tiger.mySize);
//如何设计一些私有的private的属性和方法呢?
//在构造函数中不要用this,就用普通的函数创建和变量创建就是私有的了
</script>
二、原型(prototype)
含义:
-
每个函数都有一个自带的prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法
-
作用:提取类的共性,数据共享
语法:
(1)、获取原型对象
-
每个函数都有一个内置的prototype(原型)属性
-
构造函数名.prototype//返回原型对象
-
实例对象名.__ proto __//返回原型对象
<script>
function Person(name) {
this.name = name;
}
//创建一个对象实例
var p = new Person('东东')
console.log(p);
console.log(p.__proto__); //原型对象
console.log(Person.prototype); //原型对象
var arr = new Array();
console.log(arr);
console.log(arr.__proto__);
</script>
(2)、创建原型属性
构造函数名.prototype 和 实例对象=.proto 是完全相等的
-
创建原型属性方法
类名.prototype.方法名=function(){}; 实例对象名.__proto__.方法名=function(){}
-
创建原型属性属性
类名.prototype.属性名=属性值; 实例对象名.__proto__.属性名=属性值;
-
作用:减少某些函数去重复创建,减少代码冗余,数据共享的函数与属性
<script>
function Student(name) {
this.name = name;
}
// prototype原型的好处
// 给构造函数上挂载一个原型prototype,目的是为了减少某些函数去重复创建
// 减少代码冗余
// 以后不论创建出来多少个对象,大家都共用原型属性里面的
// prototype的作用:函数与属性共享的
//1、创建共享方法
Student.prototype.study = function() {
//这个方法是共享函数,(所有student的实例都可以共享)
console.log('学习');
}
//2、创建共享属性
Student.prototype.school = '蜗牛学院';
//3、创建两个对象实例
var s1 = new Student('张三');
var s2 = new Student('李四');
console.log(s1);
console.log(s2);
s1.study();
s2.study();
console.log(s1.school);
console.log(s2.school);
//创建共享属性
s1.__proto__.age = 1;
console.log(s1.age); //1
console.log(s2.age); //1
</script>
(3)、给构造函数设置一个原型属性(prototype)
-
创建的原型对象会覆盖住原来自带的原型
-
语法:
-
类名.prototype={}
-
实例对象名.__ proto __={}//不知道行不,应该不行
<!-- 给构造函数设置一个原型,就是{},{}的原型就是Object -->
<script>
function Student(name) {
this.name = name;
}
//给student设置一个原型,就是{},
//相当于覆盖了原来自带的原型属性
Student.prototype = {
age: 18,
sex: '男',
study: function() {},
love: function() {}
}
var s = new Student('东东')
console.log(s.sex); //男
console.log(s);
</script>
二
-
创建一个对象
-
var 对象名=Object.create({内容})
-
里面的内容是创建的新原型
-
在外面通过追加写的是实例里的方法和属性
-
<script>
//1、对象默认的原型是object,
console.log({
name: '小明'
});
//2、创建一个没有原型的纯粹的对象
var obj = Object.create(null);
console.log(obj);
//3、创建一个带有原型[{run:function(){}}]的对象
var obj2 = Object.create({
//原型
run: function() {}
})
console.log(obj2);
var obj3 = Object.create({
//原型属性
name: 'n'
})
//3、给这个对象追加实例属性
obj3.sex = 'nan';
console.log(obj3);
</script>
-
调用原型上的属性和方法时,不需要加__ proto __,直接写方法名/属性名即可
-
当我们想要修改原型上的面的内容时,才需要通过__ proto __去进行修改
<script>
function phone(type, icloud, color) {
this.type = type;
this.icloud = icloud;
this.color = color;
}
phone.prototype = {
call() {
console.log(this.type);
},
message() {},
internet() {},
}
var p = new phone('iPhone12', 'gysz12b110@xx', 'white')
console.log(p);
//获取原型上的属性和方法时,不需要加__ proto __,直接写名字即可
p.call();
// 当我们想要修改原型上面的内容时, 才需要通过__ proto 才需要通过__
p.__proto__.call = function() {
console.log('重置');
}
</script>
三、构造函数方式和原型方式对比
(1)、prototype原型的好处
-
给构造函数上挂载一个原型prototype,目的是为了减少某些函数去重复创建
-
给原型上的内容创建一次就行,以后无论创建对少个对象,大家都共用
-
但是构造函数里面的内容,每new一次,就要创建一次,造成性能浪费
三、prototype原型优先级
原型模式的执行流程:(就近原则)
背景:当构造函数内部的成员与原型上的内容重名了,
寻找规则:就近原则
-
先查找构造函数实例里的属性和方法,如果有,立刻返回;
-
如果构造函数实例里面没有,则去它的原型对象里面找,如果有就返回
-
如果没有,属性返回underfined,方法返回not a function