JavaScript四种设计模式,构造函数、原型(原型对象),实例对象,对象原型,原型继承、原型链理解分析

工厂设计模式

使用工厂函数批量创建对象 工厂造出来的都是Object实例,创建对象都是Object的实例

function Person(name,age,gender){
  return {
    name:name,
    age:age,
    gender:gender,
    sayName : function(){
      console.log(this.name)
    }
  }
}

对于公共的方法会造成冗余,每次实例化都会在堆中创建一个方法实例方法

针对方法冗余 将方法声明为公共方法

var sayName = function(){
  console.log(this.name)
}
function Person(name,age,gender){
  return {
    name:name,
    age:age,
    gender:gender,
    sayName:sayName
  }
}

 无法区分种类 工厂方法模式return返回的是Object()的实例对象,而非Person()的实例对象-->(牵扯原型链继承)

构造函数模式

构造函数模式 使用new关键词批量创建对象 区分种类

解决了区分种类,没有解决方法冗余的问题

方法声明在全局,使用方法不区分Object或者Person

var sayName = function(){
  console.log(this.name)
}
function Person(name,age,gender){
  this.name = name;
  this.age = age;
  this.gender = gender;
  this.sayName = sayName
}
// new关键字作用 自动创建一个构造函数实例对象,区分种类
//              将this指向实例对象,执行函数体代码,返回实例对象
  
let p1 = new Person('terry',12,'male')
let p2 = new Person('jerry',18,'female')
console.log(p1,p2)
console.log(p1.sayName,p2.sayName)

构造函数与普通函数唯一的区别就是调用方式不同。普通函数只要使用 new 操作符调用就是构造函数,而不使用 new 操作符调用的函数就是普通函数。

公共方法实际上只能在一个对象上调用。如果这个对象需要多个方法,那么

就要在全局作用域中定义多个公共方法函数。这会导致自定义类型引用的方法冗余。

原型模式

原型模式,将实例所有的属性和方法全都写在原型对象中

可以区分种类,解决方法冗余问题

使得方法sayName仅为Person所使用

原始原型模式不对构造函数作任何处理,所有方法,属性都写在原型对象中

function Person(){
  
}
Person.prototype.name = 'jerry';
Person.prototype.age = 18;
Person.prototype.gender = 'male'
Person.prototype.sayName = function(){
  console.log(this.name);
}
var p1 = new Person();
var p2 = new Person();
// 创建出的实例属性,方法都是一致的
console.log(p1,p2)
console.log(p1.name,p2.name)
console.log(p1.sayName,p2.sayName)
Person.prototype.father = []
// p1的父亲tom
p1.father.push('tom')
// p1的父亲成为所有Person实例的父亲
console.log(p1.father,p2.father)

原型模式弱化了向构造函数传递初始化参数的能力, 会导致所有实例默认都取得相同的属性值 。

原型上的所有属性是在实例间共享的 ,利弊都很显著。

对于不同的实例应该有属于自己独特的属性副本才对。

组合模式(构造函数+原型模式)

结合构造函数模式和原型模式的特点

构造函数用于定义实例属性

原型模式用于定义方法和共享属性。

function Person(name,age,gender){
  this.name=name;
  this.age=age;
  this.gender=gender
}
// 公共方法
Person.prototype.sayName=function(){
  console.log(this.name)
}
// 公共属性
Person.prototype.type = 'Person实例'

原型

小结:在父母眼中的孩子,在儿女眼里是父母(原型继承),而在路人眼里都是陌生人

简要分析

原型、实例对象、对象原型:原型是给实例对象提供共享属性方法的对象,函数中都有一个指针prototype属性,指向的是一个原型对象。每个实例对象中有一个指针__prototype__属性,它指向它的prototype对象。

原型继承、原型链:原型对象也有自己的原型,将原型对象理解为也是一个实例对象,原型对象通过指针__prototype__属性指向它的原型,层层指向,最终指向为空null

引入:

// 构造函数是一种特殊的函数,主要用来初始化对象
// 使用构造函数来快速创建多个类似的对象,属性类似值不同
// 构造函数约定 1.命名大写字母开头 2.以new开头创建   new关键字调用函数的行为为实例化
//构造函数内部无需写return ,返回值即为新创建的对象 
//实例成员和静态成员
// 实例成员:实例对象上的属性和方法属于实例成员  p.name p.salary =() => { }
// 静态成员:构造函数中的属性和方法属于静态成员 静态成员只能通过构造函数访问,
// 静态方法中的this指向构造函数  Pig.eyes =    Pig.sayhi = () => { }
// js通过构造函数来实现面向对象的封装性,存在内存浪费
<!-- 构造函数通过原型分配的函数是所有对象所共享的 -->
<!-- 每一个构造函数都有一个prototype属性,指向另一个对象,称为原型对象 -->
<!-- 原型对象可以挂载函数,对象实例化不会多次创建原型上函数 -->
<!-- 构造函数和原型this指向都是实例化对象 -->
function Pig(uname,age){
    this.uname = uname;
    this.age = age;
    }
    // 公共的属性写到构造函数上
    // 公共的方法写到原型prototype身上
  Pig.prototype.sing = function(){
    console.log('singing');
  }
  const ldh = new Pig('ldh',55);
  console.log(ldh); 
  ldh.sing()
  // 构造函数和原型的this指向对象
  const zxy = new Pig('ldh',55)
  <!-- __proto__是JS非标准属性 -->
  <!-- 对象原型指向构造函数的原型对象 -->
 function Star(){
      
    }
    const ldh = new Star()
    console.log(ldh.__proto__);  
    console.log(ldh.__proto__ ==Star.prototype) //true
    console.log(Star.prototype.constructor == Star); //true
    // 构造函数都有它的原型方法 Star.prototype
    // 构造函数创建实例对象 new Star
    // 原型对象的属性指向它的构造函数 prototype.constructor 
    // 实例对象的属性指向它的原型  ldh.__proto__
    // 实例对象的构造函数  ldh.__proto__.constructor

原型角色

构造函数

构造对象的函数

每一个构造函数都有一个原型属性prototype,指向它的原型对象。

在构造函数中的属性方法是静态属性和静态方法,在其中的属性方法只能通过构造函数本身调用

 * 修改属性默认特性:构造函数本身的方法 静态方法只能由构造函数本身调用
 * Object.defineProperty(目标对象,属性,{配置对象})
 */
Object.defineProperty(obj,'name',{
  configurable:false,//默认对象属性是可以删除的 默认值true  改为false后该属性无法删除
  writable:true,//表示当前属性是否可写 默认值true 
  enumerable:true,//表示当前属性是否可枚举 默认值true 可枚举属性可以使用for in循环遍历
  value:'terry',//给name属性设置属性值
});
/**
 * 读取整个对象中属性特性 getOwnPropertyDescriptors(obj)
 */
console.log(Object.getOwnPropertyDescriptors(obj));
这是两个例子,构造函数中的静态方法defineProperty  getOwnpropertyDescriptors只能通过构造函数Object访问

构造函数可以创建多个实例,每个实例可以自己添加属性(自有属性)、也可以继承构造函数的属性

原型(原型对象):构造函数 .prototype

// 该构造函数所对应的原型对象
console.log(Object.prototype);
// 每一个原型对象都有指针指向构造者
console.log(Object.prototype.constructor === Object);

原型对象是构造函数通过指针prototype指向的, 职责在于提供给其他对象共享属性,构造函数通过原型分配的函数是所有实例对象所共享的,原型对象常用来挂载封装好的方法,经挂载的方法可以被所有的实例对象访问使用。

写在原型对象中的属性和方法是实例属性和方法

  function Pig(uname,age){
    this.uname = uname;
    this.age = age;
    }
    // 公共的属性写到构造函数上
    // 公共的方法写到原型prototype身上
  Pig.prototype.sing = function(){
    console.log('singing');
  }
  const ldh = new Pig('ldh',55);
  ldh.sing()

官方定义:每个函数都有一个 prototype 属性,这个属性是一个指针,指向一个对象,这个对象称为原型对象;每个对象都有一个 [[Prototype]] 属性,它同样是个指针,指向原型对象。

constructor构造者属性

小结:孩子的父母是谁,我是谁的孩子,通过我身上的血脉(constructor)指向

constructor属性作用:在原型对象中作为一个指针,指向原型对象的构造函数。

构造函数-原型prototype
构造函数与原型prototype

实例对象(对象原型)

var obj = new Object(); 
var obj1 = {};//也是构造函数创建

由构造函数new创建的实例对象

实例对象可以访问原型对象prototype的属性和方法和构造函数的属性方法

对象原型:__proto__原型

实例对象都会有一个指针属性__proto__指向构造函数的原型对象

实例对象通过指针属性__proto__原型来使用构造函数prototype原型对象的属性和方法

同一个构造函数创建的实例对象.__proto__和构造函数.prototype是等价的

console.log(Object.prototype.constructor === Object);
// 每一个实例对象都有一个指针指向原型对象
console.log(obj.__proto__ === Object.prototype);
console.log(obj.__proto__.toString() === Object.prototype.toString());
console.log(obj.__proto__.valueOf() === Object.prototype.valueOf());
// 对象实例可以访问的方法和属性 实例方法也叫原型方法 
以上结果均为true
构造函数、原型prototype、实例对象三者联系
__proto__原型的contructor属性

实例对象中指针__proto__属性(指向原型对象)也有一个constructor属性,来指向创建该实例对象的构造函数,constructor属性最终都指向构造函数

// 每一个原型对象都有指针指向构造者
console.log(Object.prototype.constructor === Object);
三者紧密联系

原型继承、原型链:

将一个对象设置为另一个对象的原型

当访问一个对象的属性(方法)时,首先查找这个对象本身,当本身没有这个属性方法时,向它的上一级原型对象查找,通过__proto__指向的prototype原型对象,依次类推

__proto__对象原型提供一个 原型对象的查找机制

var str = 'hello';
let arr = Array.from(str);
var arr1 =new Array();
console.log(arr1.__proto__.constructor === arr.__proto__.constructor);
console.log(arr1.constructor === arr.constructor);
打印结果都为true
注意实例对象是没有constructor属性的,但是为什么打印结果也为true呢
因为它继承了它的原型arr.__proto__(构造函数.propertype)的属性和方法

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值