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
})
}