06JS面向对象

本文详细介绍了JavaScript中的对象、属性描述符、工厂方法、构造函数、原型以及各种继承方式,包括原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合继承。还探讨了不同继承方式的优缺点,并给出了相关示例代码。
摘要由CSDN通过智能技术生成

JS面向对象

JS 中的对象

对象描述符 可以对这个对象做一些控制

var obj = {
    name:'why',
    age:18
}
// 数据属性描述符
// 用了属性描述符, 那么会有默认的特性
Object.defineProperty(obj, "address", {
    // 很多配置
    // value: "北京市", // 默认值undefined
    // 该特殊不可删除/也不可以重新定义属性描述符
    // configurable: false, // 默认值false
    // // 该特殊是配置对应的属性(address)是否是可以枚举
    // enumerable: true, // 默认值false
    // // 该特性是属性是否是可以赋值(写入值) 
    // writable: false // 默认值false
})
console.log(obj);
console.log(obj.address);

// 同时添加多个属性
Object.defineProperties(obj,{
    name:{
        configurable: true,
        enumerable:true,
        writable:true,
        value:"tom"
    },
    age: {
        configurable: true,
        enumerable: true,
        get: function() {
        return this._age
        },
        set: function(value) {
        this._age = value
        }
    }
})
// 获取对象的属性描述符
Object.getOwnPropertyDescriptors(obj)

工厂方法

可以通过 工厂方法 来创建出多个对象 但是这样出的对象 都是 Object 类型
可以通过采用 构造函数的方法来创建

function createPerson (name) {
    var p ={}
    p.name = name
    return p
}

var p1 = createPerson('tom')

// 构造函数
function Person (name) {
    this.name = name
}

var p2 = new Person('张三')

原型

// 我们每个对象中都有一个 [[prototype]], 这个属性可以称之为对象的原型(隐式原型)
var obj = {name:'tom'}

console.log(obj.__proto__ === Object.prototype);

console.log(Object.getPrototypeOf(obj));

// 2.原型有什么用呢?
// 当我们从一个对象中获取某一个属性时, 它会触发 [[get]] 操作
// 1. 在当前对象中去查找对应的属性, 如果找到就直接使用
// 2. 如果没有找到, 那么会沿着它的原型去查找 [[prototype]]
// obj.age = 18

console.log(obj.age);
Object.prototype.age = 185
console.log(obj.age);

//  函数同对象一样
function foo() {

}
// 函数也是一个对象  类似于  new function 的操作
console.log(foo.__proto__ === Function.prototype);

// 这些都等同于是  通过 new 操作符 创建的实例对象  该实例的 __proto__ = 构造函数的  prototype

创建对象的方案

该方案实例的对象 可以调用 Person 里面的方法
通过原型链调用

function Person(name, age, height, address) {
    this.name = name
    this.age = age
    this.height = height
    this.address = address
  }
  
  Person.prototype.eating = function() {
    console.log(this.name + "在吃东西~")
  }
  
  Person.prototype.running = function() {
    console.log(this.name + "在跑步~")
  }
  
  var p1 = new Person("why", 18, 1.88, "北京市")
  var p2 = new Person("kobe", 20, 1.98, "洛杉矶市")
  console.log(p1);
  p1.eating()
  p2.eating()

原型链

当访问一个对象的属性的时候 首先从其自身查找 没有的话 则在其 proto 上 查找 当然其 __proto __ 是其构造的 原型 他原型又同样存在 proto 这样就形成了 原型链
所有的原型链最终都指向 Object Object.proto 最终指向 null

差异

原型链继承
const p = New Person()
Student.prototype = p

构造函数继承
function Stufent(){
Person.call(this,…)
}
组合继承
Student.prototype = Person.prototype

原型式继承
Object.create()
Creates an object that has the specified prototype or that has null prototype.
就是返回了 一个原型指向 传入参数的 对象
newobj.proto = obj

寄生式继承
通过 create改变 原型的指向 然后对其添加方法和属性

寄生组合继承
结合组合继承和寄生继承
newobj.proto = Person.prototype
Student.prototype = newobj

原型链继承

通过 改变构造函数的 原型 使得 实例对象可以继承 某些方法 和属性
但是有比较明显缺陷
1.第一个弊端: 打印stu对象, 继承的属性是看不到的
2.第二个弊端: 创建出来两个stu的对象
直接修改对象上的属性, 是给本对象添加了一个新属性
获取引用, 修改引用中的值, 会相互影响
3.第三个弊端: 在前面实现类的过程中都没有传递参数

function Person() {
    this.name = '1'
    this.friends = []
}

Person.prototype.eating = function () {
    console.log(this.name + 'eating');
}

function Student() {
    this.son = 111
}

var p = new Person()

Student.prototype = p

Student.prototype.studying = function () {
    console.log(this.name + 'study');
}

var stu = new Student()

// 原型链实现继承的弊端:
// 1.第一个弊端: 打印stu对象, 继承的属性是看不到的
console.log(stu)

// 2.第二个弊端: 创建出来两个stu的对象
var stu1 = new Student()
var stu2 = new Student()

// 直接修改对象上的属性, 是给本对象添加了一个新属性
stu1.name = "kobe"
console.log(stu2.name)

// 获取引用, 修改引用中的值, 会相互影响
stu1.friends.push("kobe")

console.log(stu1.friends)
console.log(stu2.friends)

// 3.第三个弊端: 在前面实现类的过程中都没有传递参数
// var stu3 = new Student("lilei", 112)

借用构造函数

// 通过call 借用了 person 新创建了person 对象

调用了 两次父类构造函数
实例有两份属性 一份在本身 另一份在 原型对象中

function Person(name,age,friends) {
    
    //  this  指向 调用的 实例对象
    this.name = name
    this.friends = friends
    this.age = age
}

Person.prototype.eating = function () {
    console.log(this.name + 'eating');
}

function Student(name,age,friends,sno) {
    Person.call(this,name,age,friends)
    this.sno = sno
}
var p = new Person()

Student.prototype = p

Student.prototype.studying = function () {
    console.log(this.name + 'study');
}

组合借用继承

父类原型直接赋值给子类
// 这样可以解决 借用构造函数的问题

function Person(name,age,friends) {
    
    //  this  指向 调用的 实例对象
    this.name = name
    this.friends = friends
    this.age = age
}

Person.prototype.eating = function () {
    console.log(this.name + 'eating');
}

function Student(name,age,friends,sno) {
    Person.call(this,name,age,friends)
    this.sno = sno
}


Student.prototype = Person.prototype

Student.prototype.studying = function () {
    console.log(this.name + 'study');
}

原型式继承

Object.create()
Creates an object that has the specified prototype or that has null prototype.
就是返回了 一个原型指向 传入参数的 对象

newObj.proto = o

// create 函数实现

function createObj1(o) {
    var newObj = {}
    Object.setPrototypeOf(newObj,o)
    return newObj
}

function createObj2(o) {
    function Fn() {}
    Fn.prototype = o
    var newObj = new Fn()
    return newObj
}

寄生式继承

结合原型类继承和工厂模式的一种方式
先同过 create 改变 prototype 指向 然后对其添加属性和方法

var perObj = {
    running : function () {
        console.log('running');
    }
} 

function createStudent(name) {
    var stu = Object.create(perObj)
    stu.name = name
    stu.study = function (){
        console.log('study');
    }
    return stu
}

寄生组合继承

结合 组合继承 和寄生继承
子类原型 指向 x x原型指向 父类的原型
子类的 _proto 指向了父类的原型对象
A B b
B 是A的 子类 b 是 B 的实例对象
那么 b 的 proto = B,prototype
B.proto = A.prototype
因为我们只是想得到 A prototype 的方法而已

function createObject(o) {
   function Fn() {}
   Fn.prototype = o 
   return new Fn()
}

function inheritPrototype(SubType,SuperType) {
   SubType.prototype = createObject(SuperType.prototype)
   Object.defineProperty(SubType.prototype,'constructor',{
       enumerable:false,
       configurable:true,
       writable:true,
       value:SubType
   })
}

原型继承关系

Imagetext

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值