JavaScript——对象
目录对象基础认知对象字面量检索更新引用原型 prototype反射枚举 for删除 delete减少全局变量污染对象基础认知JS数据类型划分简单类型基本类型数字、字符串、布尔值、 null 、 undefined特点看似像对象、拥有方法但本身不可变引用类型全都是对象数组、函数、正则、普通对象等特点可变的键控集合key-value可自由增删属性对象核心特性对象是属性的容器每个属性由属性名 属性值组成属性名可以是任意字符串属性值可以是任意类型除 undefined JS是无类class-free语言无需提前定义结构可动态新增属性对象支持嵌套天然适合表示树形、图形类复杂数据结构原型链JS特有继承机制减少初始化时间与内存消耗对象字面量定义对象字面量是用一对大括号 {}创建对象的便捷语法可直接定义多个 名/值 对。语法规则1属性名规则合法JS标识符可省略引号如 first_name: “xxx” 含 - 、空格等特殊字符必须加引号如 “first-name”: “xxx” 2 属性值可以是任意表达式支持对象嵌套示例varflight{airline:Oceanic,number:815,departure:{IATA:SYD,time:2004-09-22 14:55}//嵌套};检索1两种取值语法点语法.仅支持合法标识符可读性更强优先使用flight.departure.IATA中括号语法[ ]支持任意字符串属性名stooge[first-name]2取值规则1.访问不存在的属性返回 undefined2.短路运算符的两个经典用法|| 给属性设置默认值letstatusflight.status||unknown;上面的语句可以理解为status 要么是 flight.status要么是 “unknow”因为 || 本身就代表 或者的意思 规避 undefined 取值报错防止 TypeError 如果你检索到了一个undefined 的值就会抛出TypeError异常而 就能避免错误这就类似于Java访问到了一个空链表的next此时的链表已经是空再访问null的next编译系统完全无法识别应该去往哪里就会抛出异常flight.equipment//它的取值类型是 undefinedflight.equipment.model// throw “TypeError”flight.equipmentflight.equipment.model为什么 能避免报错呢本质上是让编译系统先判断 flight.equipment.model 的上一层 flight.equipment 是否为空如果上一层已经为null了那就不需要再执行下一个判断继续运行下一条语句了更新1赋值规则属性已存在赋值直接覆盖原有值属性不存在赋值会动态新增该属性JS对象可动态扩展2 示例// 覆盖已有属性stooge[first-name]Jerome;// 动态新增属性stooge.nicknameCurly;引用1核心规则对象通过引用传递永远不会被拷贝多个变量指向同一个对象时修改任意一个变量所有变量都会同步变化。2 两种场景示例多个变量引用同一个对象letxstooge;x.nicknameCurly;letnickstooge.nickname// x.nickname 和 nick 都指向 “Curly”链式赋值所有变量指向同一个空对象vara{},b{},c{};// 三个独立空对象abc{};// a、b、c 都指向同一个空对象此时a改变了 b也会改变原型 prototype1原型基础概念所有字面量创建的对象原型默认指向 Object.prototype原型的核心作用实现属性委托继承子类对象可复用原型的属性节省内存2 手写原型继承 Object.beget 底层原理if(typeofObject.beget!function){Object.begetfunction(o){varFfunction(){};// 空构造函数充当“桥梁”F.prototypeo;// 将构造函数原型指向传入的原型对象returnnewF();// 返回新实例实例原型自动绑定 o};}3原型核心特性更新时原型连接不生效写屏蔽读继承给子对象新增同名属性只会修改自身完全不影响原型对象varanother_stoogeObject.beget(stooge);another_stooge[first-name]Harry;// 仅修改自身stooge 完全不变检索时原型链向上委托读取属性时先查自身没有就顺着原型链向上找直到 Object.prototype 全程找不到则返回 undefined原型动态性给原型新增属性所有基于该原型创建的对象会立刻继承该属性stooge.professionactor;another_stooge.profession;// 自动读取原型属性结果为 actor反射1 定义反射动态检测对象拥有哪些属性核心工具为typeof和hasOwnProperty。2 typeof 运算符作用检测属性值的类型但会把原型链上继承的方法如 toString 、 constructor 一并识别为 function。3 hasOwnProperty作用判断属性是否为对象自身独有完全不检查原型链返回值 true 自身属性 false 继承属性 / 不存在示例flight.hasOwnProperty(number);// true自身属性flight.hasOwnProperty(constructor);// false原型继承属性枚举 for1 for…in 遍历对象作用遍历对象所有属性名key致命缺陷会遍历原型链上继承的属性、方法属性遍历顺序不固定标准写法必须搭配 hasOwnProperty 过滤原型属性for(nameinanother_stooge){// 只遍历自身属性排除原型继承的方法if(typeofanother_stooge[name]!function){document.writeln(name: another_stooge[name]);}}2替代方案推荐手动定义属性数组 普通 for 循环顺序可控、不触碰原型链更稳定可靠。即for(let i0 ; inums.length ; i)这里再补充一个for…offor…of 遍历值专门给数组/可迭代对象用作用ES6 新增专门遍历数组、Map、Set、字符串等可迭代对象拿值value。特点遍历值本身不是下标完全不碰原型链安全干净可以配合 break 、 continue不能直接遍历普通对象普通对象不是可迭代对象示例constarr[10,20,30];for(letvalueofarr){console.log(value);// 输出10 20 30}删除 delete1 delete 运算符规则仅删除对象自身属性完全不触碰原型链删除后若原型存在同名属性会自动浮现原型的属性值2 示例deleteanother_stooge.nickname;// 删除自身属性后会读取原型 stooge 的 nicknameanother_stooge.nickname;减少全局变量污染1 全局变量的弊端全局变量过多易出现命名冲突、代码耦合度高、灵活性变差。2 解决方案单一全局变量命名空间只创建一个顶层全局对象所有变量、对象都挂载到这个对象上示例letMYAPP{};// 唯一全局变量MYAPP.stooge{first-name:Joe};MYAPP.flight{airline:Oceanic};3优势大幅降低命名冲突概率代码结构清晰可读性更强。