10TypeScript泛型进阶

一. 写在前面

  • 本次内容全部是js的,没有ts内容,学习这些内容是为了之后更好的学习ts,如果不学习这些内容可能会导致之后ts的学习有地方难以理解

二. 面向对象之原型

  • 假设我需要用js造一个小兵,以下是基础代码
js 复制代码
// JavaScript 造一个小兵 
const 近战兵 = {
  兵种:"近战",
  血量:1488,
  物理攻击力:60,
  护甲:180,
  金钱:42,
  补刀奖励:16,
  出生:function (){/*出生动画*/},
  死亡:function (){/*死亡动画*/},
  攻击:function (){/*攻击特效*/ },
  行走:function (){/*行走动画*/ },
}
兵营(近战兵)
  • 需求: 造100个
    • 有两种方式,第一种写100遍,这种方式明显很不合理
js 复制代码
const 近战兵1={/*略*/}
const 近战兵2={/*略*/}
/* ... */
const 近战兵100={/*略*/}
兵营(近战兵1, 近战兵2, ···, 近战兵100)
  • 第二种方式,使用循环,但是这种方式还有问题,太浪费内存了
js 复制代码
const list = [] 
for (let i=0; i<100; i++) {
  list.push({
    id: i,
    兵种: '近战',
    血量: 1488,
    物理攻击力: 60,
    护甲: 180,
    金钱: 42,
    补刀奖励: 16,
    出生: function(){/*出生动画*/},
    死亡: function(){/*死亡动画*/},
    攻击: function(){/*攻击特效*/},
    行走: function(){/行走动画*/},
  })
}
兵营(...list)
  • 我们通过分析,可以发现,金钱,补刀奖励,以及四个函数是一样的,共用的,我们期望实现以下效果
js 复制代码
{
  id: 1,
  血量: 1488,
  物理攻击力: 60,
  护甲: 180,
  more: 近战兵公有属性
}
{
  id: 2,
  血量: 1488,
  物理攻击力: 60,
  护甲: 180,
  more: 近战兵公有属性
} 
近战兵公有属性 = {
  兵种: '近战',
  金钱: 42,
  补刀奖励: 16,
  出生: function(){/*出生动画*/},
  死亡: function(){/*死亡动画*/},
  攻击: function(){/*攻击特效*/},
  行走: function(){/*行走动画*/},
}
  • 我们通过下图来体会一下这样做的好处,从1100个属性降到507个属性,大大减少了内存,我们的核心思想就是把所有的属性分成独有属性和共有属性
  • 经过上面这个步骤之后,我们可以得到造100个士兵,同时内存尽量少的方法
js 复制代码
const 近战兵公有属性 = {
  兵种: '近战',
  金钱: 42,
  补刀奖励: 16,
  出生: function(){/*出生动画*/},
  死亡: function(){/*死亡动画*/},
  攻击: function(){/*攻击特效*/},
  行走: function(){/*行走动画*/},
}
for (let i=0; i<100; i++) {
  const 近战兵 = {
    id: i,
    血量: 1488,
    物理攻击力: 60,
    护甲: 180,
  }
  近战兵.__proto__ = 近战兵公有属性 // 隐藏属性指向近战兵公有属性
  list.push(近战兵)
}
兵营(...list)

三. 再次去优化代码

  • 目前代码还存在的问题: 代码过于分散,分成了两部分代码去创建士兵,我们可以这样去优化
js 复制代码
// soldier.js
export const 创建近战兵 = function(id) {
  const 近战兵 = {
    id: i,
    血量: 1488,
    物理攻击力: 60,
    护甲: 180,
  }
  近战兵.__proto__ = 近战兵公有属性
  return 近战兵
}
const 近战兵公有属性 = {
  兵种: '近战',
  金钱: 42,
  补刀奖励: 16,
  出生: function(){/*出生动画*/},
  死亡: function(){/*死亡动画*/},
  攻击: function(){/*攻击特效*/},
  行走: function(){/*行走动画*/},
}
// main.js
import {创建近战兵} from './soldier'
const list = []
for (let i=0; i<100; i++) {
  list.push(创建近战兵(i))
}
兵营(...list)
  • 目前还存在的缺点,创建近战兵和近战兵公有属性不够内聚,这两段代码非常互相依赖,但是仅仅靠近战兵.__proto__ = 近战兵公有属性去关联
    • 这里解释一下什么是高内聚低耦合,所谓的高内聚就是该在一起的代码不要分开,低耦合就是能分开的代码尽量不要放在一起
js 复制代码
// 进一步优化代码,让代码内聚,这样子之后,这两段代码彼此无法分开 
export const 创建近战兵 = function(id) {
  const 近战兵 = {
    id: i,
    血量: 1488,
    物理攻击力: 60,
    护甲: 180,
  }
  近战兵.__proto__ = 创建近战兵.prototype
  return 近战兵
}
const 创建近战兵.prototype = {
  constructor: 创建近战兵
  兵种: '近战',
  金钱: 42,
  补刀奖励: 16,
  出生: function(){/*出生动画*/},
  死亡: function(){/*死亡动画*/},
  攻击: function(){/*攻击特效*/},
  行走: function(){/*行走动画*/},
}
  • 以上这段代码非常经典,于是js之父决定把这段代码推广给每一个写js的程序员
js 复制代码
// 进一步优化代码,让代码内聚,这样子之后,这两段代码彼此无法分开 
export const 创建近战兵 = function(id) {
  const 近战兵 = {
    id: i,
    血量: 1488,
    物理攻击力: 60,
    护甲: 180,
  } // const 近战兵,这句不需要写,肯定会创建一个对象,但是要把独有属性写清楚
  近战兵.__proto__ = 创建近战兵.prototype // 这句不需要写,每个对象都肯定要加
  return 近战兵 // 不需要写,每一个构造函数肯定要return一个对象
}
const 创建近战兵.prototype = { // 这句固定下来就叫prototype
  constructor: 创建近战兵 // 这句不需要写,自动加一个constructor,指向上面函数,这样就做到了高内聚
  兵种: '近战',
  金钱: 42,
  补刀奖励: 16,
  出生: function(){/*出生动画*/},
  死亡: function(){/*死亡动画*/},
  攻击: function(){/*攻击特效*/},
  行走: function(){/*行走动画*/},
}
  • 其实剩下的代码只剩下独有属性和共有属性
js 复制代码
// soldier.js
export const 近战兵 = function(id) {
  this.id = id
  this.血量 = 1488
  this.物理攻击力 = 60
  this.护甲 = 180
}
近战兵.prototype.兵种 = '近战'
近战兵.prototype.金钱 = 42
近战兵.prototype.补刀奖励 = 16
近战兵.prototype.出生 = function(){/*出生动画*/}
近战兵.prototype.死亡 = function(){/*死亡动画*/}
近战兵.prototype.攻击 = function(){/*攻击特效*/}
近战兵.prototype.行走 = function(){/*行走动画*/}

// main.js
import {近战兵} from './soldier'
const list = []
for (let i=0; i<100; i++) {
  list.push(new 近战兵(i)) // 注意这里的new
}
  • 这段代码还能优化吗?通过浅拷贝实现优化
js 复制代码
// soldier.js
export const 近战兵 = function(id) {
  copy(this, { id: id, 血量: 1488, 物理攻击力: 60, 护甲: 180})
}

近战兵.prototype = {
  constructor: 近战兵, // 这样写会把constructor覆盖,因此这里需要加回来
  兵种: '近战'
  金钱 : 42
  补刀奖励: 16
  出生 : function(){/*出生动画*/}
  死亡 : function(){/*死亡动画*/}
  攻击 : function(){/*攻击特效*/}
  行走 : function(){/*行走动画*/}
}

四. new做了哪些事

  • 创建一个完全空的对象,放到this上面 this = {}
  • 把这个对象的隐藏属性指向公有属性 this.__proto__ = 近战兵.prototypes
  • 返回this,return this
  • 近战兵.protoType 这件事情,包括里面的constructor: 近战兵都是js做的,并非new去做的
    • 当在浏览器里面声明一个非箭头函数然后通过console.dir,即可发现自带prototype和constructor

五. 总结: JS如何创建对象

  1. 以new为语法糖
js 复制代码
var a = {} // 这只是简写
var a = new Object() // 实际上是这样写
// 同理
var array = []
var array = new Array()
  1. 用构造函数给对象添加独有尾性
  2. 用构造函数的prototype容纳共有隐性
  3. 使用属性查找规则 1. 读取obj的'x'属性时,先看obj的独有属性有没有x 2. 再看obj的共有属性有没有x 3. 再去看obj的共有属性的共有属性有没有x 4. 直到共有属性为null,则认为obj.x不存在

六. js如何知道共有属性有哪些

  • 以前用的是obj.__proto__这种形式
  • 现在用obj.[[prototype]]

七. 一些面试题

  • 什么原型?
    • 第一题
js 复制代码
const obj = new 近战兵(i)
// 请问obj的原型是,答案: 1 和 2,他们是相等的
// 1. 近战兵.prototype
// 2. obj.__proto__ 或者 obj.[[prototype]]
  • 第二题
js 复制代码
const fn = function() {}
// 函数比较特殊会有一个prototype属性
// 请问fn的原型是? 2 和 3,这里的关键点是要把fn当作一个obj,1是把fn当作函数去解释,每一个非箭头函数都有一个prototype
// 1. fn.prototype
// 2. fn.__proto__
// 3. Function.prototype
  • 第三题
js 复制代码
// Function的原型是什么? 
// Function.prototype不是它的原型,是这个函数构造出来的对象的原型
Function.__proto__ === Function.prototype // true,函数的原型是其共有的属性
// Function的构造函数是什么? 是它本身
Function.prototype.constructor === Function // true
// 1. 浏览器构造了Function
// 2. 浏览器卸了代码 Function.constructor = Function
  • 总结: 原型就是指一个对象的共有属性所在地

八. 画出js世界

九. 相关文章

相关推荐
重生之后端学习16 分钟前
02-前端Web开发(JS+Vue+Ajax)
java·开发语言·前端·javascript·vue.js
繁依Fanyi1 小时前
用 CodeBuddy 实现「IdeaSpark 每日灵感卡」:一场 UI 与灵感的极简之旅
开发语言·前端·游戏·ui·编辑器·codebuddy首席试玩官
来自星星的坤3 小时前
【Vue 3 + Vue Router 4】如何正确重置路由实例(resetRouter)——避免“VueRouter is not defined”错误
前端·javascript·vue.js
香蕉可乐荷包蛋7 小时前
浅入ES5、ES6(ES2015)、ES2023(ES14)版本对比,及使用建议---ES6就够用(个人觉得)
前端·javascript·es6
未来之窗软件服务8 小时前
资源管理器必要性———仙盟创梦IDE
前端·javascript·ide·仙盟创梦ide
liuyang___9 小时前
第一次经历项目上线
前端·typescript
西哥写代码9 小时前
基于cornerstone3D的dicom影像浏览器 第十八章 自定义序列自动播放条
前端·javascript·vue
清风细雨_林木木9 小时前
Vue 中生成源码映射文件,配置 map
前端·javascript·vue.js
FungLeo10 小时前
node 后端和浏览器前端,有关 RSA 非对称加密的完整实践, 前后端匹配的代码演示
前端·非对称加密·rsa 加密·node 后端
不灭锦鲤10 小时前
xss-labs靶场第11-14关基础详解
前端·xss