这里是修真院前端小课堂,每篇分享文从【背景介绍】【知识剖析】【常见问题】【解决方案】【编码实战】【扩展思考】【更多讨论】【参考文献】八个方面深度解析前端知识/技能。
本篇分享的是:【 简述JS中的面向对象编程 】
(1)背景介绍:
“面向对象编程”(Object-Oriented Programming,缩写为OOP)是目前主流的编程范式。它的核心思想是将真实世界中各种复杂的关系,
抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。面向对象的语言有一个标志,就是类的概念,
通过类可以创建任意多个具有相同属性和方法的对象。
(2)知识剖析:
1.原型链
JavaScript 常被描述为一种基于原型的语言 (prototype-based
language)——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype
chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
2.constructor和prototype属性
prototype 属性:继承成员被定义的地方,继承的属性和方法是定义在 prototype 属性之上的。然后每个对象实例都具有 constructor 属性,
它指向创建该实例的构造器函数。
js如何创建对象?
直接创建
使用函数创建
使用构造函数
用原型链
具体见demo
//直接创建
let person = {
name: "mike",
age: "20",
speak: function () {
console.log("nmsl");
}
};
console.log(person.name);
speak();
//使用函数创建(工厂模式)
unctiofn createPerson(name,age) {
//1.创建空对象
let per = {};
//2.给对象添加属性和方法
per.name = name;
per.age = age;
per.speak = function () {
console.log("halo, "+name);
};
//把创建的对象返回
return per;
}
let per1 = createPerson("大雄",13);
let per2 = createPerson("静香",13);
console.log(per1);
console.log(per2);
console.log(per1 instanceof createPerson);//判断是否属于这个函数
//构造函数,首字母大写
function CreatePerson(name,age) {
//吧所以属性和方法挂在this指针上,将来this指向谁,这个属性和方法就添加在谁身上
this.name = name;
this.age = age;
this.speak = function () {
console.log("halo"+this.name);
}
}
let per = new CreatePerson("胖虎",13);
per.speak();
//object构造函数
let person1 = new Object();
person1.name = 'Chris';
person1['age'] = 38;
person1.greeting = function() {
alert('Hi! I\'m ' + this.name + '.');
};
person1.greeting();
//还可以将对象文本传递给Object() 构造函数作为参数, 以便用属性/方法填充它
var person1 = new Object({
name : 'Chris',
age : 38,
greeting : function() {
alert('Hi! I\'m ' + this.name + '.');
}
});
//create 打印太输出
var person2 = Object.create(person1);
person2.name;
person2.greeting();
JavaScript 支持面向对象式编程,与主流的面向对象式编程语言不同,JavaScript 并没有类(class)的概念,(es6之前)
而是使用基于原型(prototype)的继承方式。相应的,JavaScript 中的构造函数也很特殊,如果不使用 new 调用,则和普通函数一样。
作为又一项约定俗成的准则,构造函数以大写字母开头,提醒调用者使用正确的方式调用。如果调用正确,this 绑定到新创建的对象上。
工厂模式:重复函数,浪费资源,每实例化一个对象就会占用新的内存资源
使用自定义的构造函数来创建对象,它与工厂方法区别在于:1.没有显式地创建对象2.直接将属性和方法赋值给this对象;
3.没有return语句;此外,要创建Person的实例,必须使用new关键字,以Person函数为构造函数,传递参数完成对象创建;
实际创建经过以下4个过程:
-
创建一个对象
2.将函数的作用域赋给新对象(因此this指向这个新对象,如:person1)
3.执行构造函数的代码
4.返回该对象
用原型构造的时候:JS每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,
它是所有通过new操作符使用函数创建的实例的原型对象。原型对象最大特点是,所有对象实例共享它所包含的属性和方法,
也就是说,所有在原型对象中创建的属性或方法都直接被所有对象实例共享。
面向对象三大特性,封装,继承,多态.
//所谓多态,就是指一个引用类型在不同情况下的多种状态。在java中多态是指通过指向父类的引用,来调用在不同子类中实现的方法。
//js实际上是无态的,是一种动态语言,一个变量的类型是在运行的过程中由js引擎来决定的,所以说js天生就支持多态。
// 主人类
function Master() {
// 主人玩耍动物
this.feed = function(animal) {
console.log("主人玩耍" + animal.name);
console.log("类:" + animal.constructor);
};
}
// 猫类
function Cat(name) {
this.name = name;
}
// 狗类
function Dog(name) {
this.name = name;
}
var cat = new Cat("小猫咪");
var dog = new Dog("小狗狗");
var master = new Master();
master.feed(cat);
master.feed(dog);
// 这样做的优点在于Master不需要改变,如果要扩展加入其它的动物,
// 只需要加一个猴子类就好了
//将不同类的相同之处取出封装成独立的类
function Stu() {
this.name = "学生";
}
Stu.prototype.free = function() {
console.log("free");
};
function MidStu() {
this.stu = Stu;// 将Stu函数体赋值给stu;
/*
* 执行stu里面的函数体
* 就相当于执行了这句话 :this.name = "学生";
*/
this.stu();// 通过对象冒充,来实现继承。
delete this.stu;// 删除对象的引用。
}
var stu1 = new MidStu();
console.log(stu1); // 拥有这个属性 this.name = "学生";
stu1.free(); //prototype的free这个属性不存在
function Person(age) {
var age = age;// 私有变量
this.showAge = function() {// 特权方法
console.log(age);
};
}
var p1 = new Person(20);// 新建对象p1
p1.showAge();// -> 20 这个20是闭包
// 闭包简单的说就是函数里的函数,里面的函数可以用外面的变量
// 为什么这个函数体里面存了一份age的数据。
//但是如果使用prototype来写的函数,无法访问私有变量
Person.prototype.myAge = function() {
console.log(age);
};
var p1 = new Person(20);// 新建对象p1
p1.myAge();// 报错 age is not defined
//其实这也印证了:闭包就是函数里面包函数,由于prototype是通过函数名,指到其他内存空间独立的函数体,因此没法取得闭包的作用域变量。
(3)常见问题:
从编程的思想角度什么是面向对象编程
(4)解决方案:
1,面向过程:面向对象关注的是解决问题的步骤,
2.面向对象,关注的是解决问题所需的对象(内容,角色),然后根据业务逻辑按一定规则调用这些对象的
相关功能,方法。万物皆为对象,每一个具体的物品就是一个对象
(5)编码实战:
demo
(6)拓展思考:
如何在js中使用面向对象?
(1)访问对象的属性 1.点语法(.)和[ ]访问某一个属性
使用点语法访问属性,点后直接跟属性名 <br/>
使用[ ]访问属性,[ ]里属性字符串必须是字符串类型的数据 或 保存属性名字的字符串变量
(7)参考文献:
(8)更多讨论:
Q1:提问人:es6中class是什么
A1:类实际上是个“特殊的函数”,就像你能够定义的函数表达式和函数声明一样,类语法有两个组成部分:类表达式和类声明。一个类的类体是一对花括号/大括号 {} 中的部分。这是你定义类成员的位置,如方法或构造函数。
Q2:提问人:jason对象是什么
A2:json始于JavaScript,现已被广泛用来做数据接口交互。
var obj = {
name:'张三',
age:'12',
speak(){//es6下function可省略
alert(`hi,im ${this.name},have ${this.age}years old.`);
}
}
obj.speak();
Q3:继承模式是什么
A3:1).原型式继承. 可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅复制。而复制得到的副本还可以得到进一步改造。
2).寄生式继承. 与原型式继承非常相似.也是基于某个对象或某些信息创建一个对象,然后增强对象,最后返回对象。为了解决组合继承模式由于多次调用超类型构造函数而导致的低效率问题,可以将这个模式与组合继承一起使用。
3).寄生组合式继承. 集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。