面向过程编程 POP(Process-oriented programming):分析出解决问题需要的步骤,然后用函数把这些步骤一步步实现,使用的时候在一个一个依次调用就行了。
面向对象编程:把事务分解成一个个对象,然后由对象间分工合作实现事务。
面向对象的思维特点:
面向对象编程我们考虑的时有哪些对象,按照面向对象的思维特点,不断的创建对象,使用队形,指挥对象做事情。
在 javaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,如:字符串,数值,数组,函数等。
对象是由属性和方法组成的:
创建类:
类的继承:
class Son extends Father {}
注意:constructor中 super关键字 必须在子类 this前调用
let that
class Father {
constructor(x, y) {
this.x = x
this.y = y
}
sum() {
return this.x + this.y
}
}
class Son extends Father {
constructor(x, y) {
super(x, y) // constructor中 super关键字 必须在子类 this前调用
this.x = x
this.y = y
this.start()
that = this // 验证this 指向
}
sum(){
console.log('对于重名方法属性,就近调用,并调用原父类方法的值:', super.sum())
}
start(){
console.log('Son实例化了一个类对象');
}
}
const test = new Son(3, 9)
test.sum()
console.log(that === this) // constructor 里面的this 指向的是 创建的实例对象。
Tips:
在典型的OOP的语言中(如Java),都存在类的概念,类就是对象的模板,对象就是类的实例,但在ES6之前,JS中并没用引入类的概念
创建对象可以通过以下三种方式:
// new Object()创建对象
let obj1 = new Object()
// 对象字面量创建对象
let obj2 = {}
// 构造函数
function Star(name, age) {
this.uname = name // 类默认有 ClassName.name 方法,返回对象名,。请不要使用name 命名
this.age = age
this.sing = function () {
console.log("构造函数创建对象")
}
}
// 构造函数创建对象
let obj3 = new Star("obj", 13)
console.log(obj1)
console.log(obj3)
new 在执行时会做的事情:
实例成员:就是构造函数内部通过this添加的成员,实例成员只能通过实例化的对象来访问
静态成员:在构造函数本身上添加的成员。静态成员只能通过构造函数来访问。
function Star2(name) {
this.uname = name
}
let obj4 = new Star2('name-test')
// 访问实例成员
console.log(Star2.uname); // undefined
// 访问静态成员
Star2.sex = '1'
console.log(Star2.sex);
console.log(obj4.sex); // undefined
Tips: 构造函数很好用,但会存在浪费内存的问题。实例化对象时会将其中的复杂数据类型(函数,)单独开辟内存空间存放,如果有多个实例化对象将会造成不必要的资源浪费。引入构造函数原型解决
构造函数通过原型分配的函数是所有对象共享的。Javascript规定,每一个构造函数都有个 prototype属性,指向另一个对象。注意这个 prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
通过把那些不变的方法,直接定义在 prototype对象上,实现所有的对象实例共享这些方法。
function Star2(name) {
this.uname = name
}
Star2.prototype.sing = function () {
console.log('test');
}
let obj4 = new Star2('name-test')
const obj5 = new Star2('name-test2')
console.log(obj4.sing === obj5.sing) // true
// 对象身上系统会自己添加一个 __proto__指向构造函数的原型对象 prototype
console.log(obj4.__proto__ === Star2.prototype)
Tips:
obj4.sing
)的执行顺序:先查看自身是否有sing方法,有则执行。没有则通过 __proto__去构造函数原型对象 prototype身上去査找 sing这个方法对象原型( proto)和构造函数( prototype)原型对象里面都有个属性 constructor属性, constructor我们称为构造函数,因为它指回构造函数本身。
Constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数
function Star2(name) {
this.uname = name
}
Star2.prototype = {
// constructor 指回原来的构造函数
constructor: Star2,
sing: function(){
// ..code
}
}
let obj4 = new Star2('name-test')
console.log(Star2.prototype.constructor === obj4.__proto__.constructor)
如果修改了原来的原型对象,给原型对象赋值的是另一个对象,则必须手动的利用 constructor 指回原来的构造函数。否则类的实体将会是新赋值的这个对象(不会继承原有方法)
构造函数,实例,原型对象三者之间的关系:
function Star2(name) {
this.uname = name
}
Star2.prototype = {
// constructor 指回原来的构造函数
constructor: Star2,
sing: function(){
// ..code
}
}
const obj = new Star2('name')
// 只要是对象就有 __proto__ 原型,指向原型对象
console.log(Star2.prototype)
// Star2原型对象里面的 __proto__原型指向的是 Object.prototype
console.log(Star2.prototype.__proto__ ==== Object.prototype)
// Object.prototype.__proto__ 指向 null
console.log(Object.prototype.__proto__)
js成员的查找机制是依照原型链从下至上的:
console.log(Array.prototype)
// 扩展内置对象方法。
Array.prototype.sum = function () {
let sum = 0
this.forEach((num) => {
sum += num
})
return sum
}
// let arr = new Array(1, 2, 3, 4, 'a')
let arr = [1, 2, 3, 4, "a"]
console.log(arr.sum())
ES6之前并没有提供 extends继承。可以通过构造函数+原型对象模拟实现继承,被称为组合继承
调用这个函数,修改函数运行时的 this指向
func.call(thisArg, arg1, ...)
function fn() {
console.log("fn-1")
// 其中this 默认指向其调用者。
console.log(this)
}
// 函数调用call 会被执行, this === window
fn.call()
// 改变this指向 this == Object
fn.call({ uname: "andy" })
function Father(uname, age) {
this.uname = uname
this.age = age
}
Father.prototype.money = function () {
console.log("1000")
}
function Son(uname, age, sex = 1) {
// 父构造函数中的this原本指向其实例化对象。需要 将子类的 this传入父级,完成继承
// 这里继承了构造函数,并没继承父的原型方法
Father.call(this, uname, age)
this.sex = sex
}
// 此种方式传递继承,如果修改了子原型对象则父级也会跟着变化
// Son.prototype = Father.prototype
// 通过一个 新实例化对象完成原型的继承
Son.prototype = new Father()
// 利用对象的形式修改了原型对象,需要利用 constructor 指回原构造函数
Son.prototype.constructor = Son
Son.prototype.call = function (num = null) {
console.log(num)
}
let son = new Son("name", 17)
son.money()
console.log(Father.prototype)
console.log("\n")
console.log(Son.prototype)
typeof className === function
类可以理解为构造函数的另一种写法
通过 class关键字定义的类, 同样拥有通过构造函数定义类的特点:
ES6的类它的绝对大部分功能,ES5都可以做到,新的 class写法只是让对象原型的写法更加加清晰、更像面向对象编程的语法而已。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。