js 没错也报错怎么办_js原型链初探

什么是对象?

一般资料上是说 : 对象是有多个属性构成.....
但是说实在话 , 真的感觉有点懵!!!

从头开始认识一下对象!!!

  1. 对象是一个复杂类型 , 由基本类型组成
var name = "张三"
var age = 18
var gender = "male"

// 这些基本类型组合在一起是有意义的 , 那么可不可以拿个东西把他们放在一起???
那就用一个"对象" , 放一下吧
var person = {
    'name' : '张三',
    'age' : 18,
    gender: 'male',
}
  1. 对象的本质是一个hash表
hash表样例

| key | value | | ---- | ----- | | a | 1 | | b | 2 | | c | 3 |

哈希表: 存储键值对的表格

{ ... } 花括号是不是就像画了一张表!!!

里面的基本类型组成的 x:y, 结构不就是 key和value吗!!!

  1. 属性 <==> x:y, 对应着这样的结构
一组键值对 , 就是一个属性
  1. 内存分配
前面说了 , 对象是基本类型的组合
基本类型通常都是以字节为单位 , 分配内存的 , Number:8个字节 String:2个字节单位
但是对象却可能包含着多个简单类型 , 所以需要分配的空间要 超过基本单位很多

基本类型的内存分配策略失效!!!

stack 内存分配失效 , heap内存闪亮登场

  1. 由于内存机制不同 , 所以不可以转换成基本类型的数据
一般来说可以转字符串 toString
  1. 对象的多层嵌套 , 是对树结构的最好模拟!!!

对象的内存结构

js内存分为代码区和数据区
数据区又分为stack内存 和 heap堆内存

stack内存:

​ 线性表的结构 , 便于数据的查找 , 但是数据插入 , 删改 , 特别浪费性能

​ 因为后面的元素要挨个后移

heap堆内存:

​ 堆内存是链表结构的 , 便于数据的改动 , 查找速度可以优化「二分法」

小结:

因为对象由于其结构复杂性的要求 , 应该放在heap内存中

基本数据为了保证查询速度 , 数据放在stack内存

变量提升 , 在代码区命名

内存结构

  1. 代码区+stack+heap
  2. 一个数字占64位 , 一个字符占16位
  3. 简单 -->stack
  4. 复杂 -->heap 「stack存地址」
  5. js没有指针的明确概念
  6. stack地址引用

循环引用

var obj = {}
obj.self = obj
// 那么obj.self.self.self 是什么呢?   画内存图理解
面试题
var a = {n:1}
var b = a
a.x = a = {n:2}

alert(a.x) ?  ==>undefined
alert(b.x) ?  ==>[Object obejct]

分析一下为什么?

  1. 关键a.x = a = {n:2}
  2. 浏览器是从左到右分析代码的 , 看到a.x时 , a是{n:1}的地址
  3. 然后把a的地址赋值给a.x属性
  4. 最后把{n:2} 的地址赋值给a

一画内存图 , 就清楚了!!!

垃圾回收

如果一个对象没有被引用 , 那他就是垃圾 , 内存就应该被回收

画内存图 , 具体分析

动手 , 不要动脑!!!

内存泄漏

ie6 的bug
关闭网页 , document 对象死了
但是上面监听的函数却依然在内存中 , 导致内存不够用 , 就是内存泄漏

深拷贝和浅拷贝

深拷贝 , 就是值复制一份 , 覆盖到stack
所以基本类型默认是深拷贝
var a='张三'
var b=a
console.log(b) //'张三'
浅拷贝 , 对象stack存的是地址 , 复制覆盖到stack的也是地址
会造成如下结果:
var obj = {name:'sun'}
var obj2 = obj
obj2.name = '涵涵'
console.log(obj1.name)  //涵涵

修改obj2的属性 , obj也改变了

是因为obj和obj2引用了同一块内存

这就是浅拷贝

对象的深拷贝: 新开辟一个内存 , 复制obj的信息

js对象相关乱象

空值乱象

在内存分配一个空间 , 起好名字 ,但是暂时还没想好放什么数据!!!
怎么处理这种情况?
  1. js默认进行初始化为空
  2. js对于基本类型的空值为undefind
var a
console.log(a)  // undefind

奇怪的地方来了 , js对于的对象类型的初始化 却是null

用null表示对象的值为空!

key引号乱象

定义时 , key可以不加引号
var obj = {
    name:'张三',
    age:18
}
读取值 , 却必须加引号
obj['name']
这一切都是js的错误

实际上定义的时候也是应该加上单引号的 , 但是js为了方便写代码的人 , 在编译器自动帮人加了 , 小白是不知道的

读数据的时候自然会犯错 , 太坑了

所以语法糖 , 并不一定是好事!!!

语法糖的缺陷
var obj = {
    9a:"hah"
}// 报错 , 9a作为变量声明错误 , js编译器没有那么聪明
var obj = {
    "9a":"hah"
}// 可以

var obj2 = {
    a_b:'xix'
}// 报错 , 不支持 a_b
var obj2 = {
    'a_b':'xix'
}

所以 : 语法糖的能力要弱一些 , key加引号 能力会强一些

但是 , 奈何不加引号简单啊 , 所以还是普及开来了!!! 人性如此!

类型错误

null 是object
typeof null //object
function 是function 而不是对像
var xxx = function() {
    console.log('hah')
}
typeof xxx  //function

instace of 和 value of

instance of 判断对象是否是父对象的实例
a instance of b  // a是否是b的实例
value of 用来判断变量存储的基本数据 , 只适用于基本类型

对象的关键字

| 关键字 | 作用 | | ----------- | ------------ | | delete | 删除属性 | | in | 查找属性 | | typeof | 查看基本类型 | | value of | 值 | | instance of | 实例 |

属性的删除

delete 关键字

var obj = {
    name:'张三'
}
delete obj['name']

属性的查找

in 关键字

'name' in obj

对象类型的判断

typeof 关键字

var obj = {}
var a = "hah"
typeof obj  // object
typeof a  // string

不是对象的对象

for in 遍历对象

var obj = {
    name:'sun',
    age:12
}
for(var key in obj) {
    console.log(key)  //打印key
    console.log(obj.key)  //打印值失败  
    // 因为obj.key <==>obj.'name' , 这样的语法是错误的
    console.log(obj[key])
}

function是一个关键字

为什么要对函数对象搞特殊?

创建数组

var a = []

创建对象

var obj = {}

但是创建函数

function xxx() {
    ...
}

却需要用关键字去创建? 同为对象 , 为什么函数对象要搞特殊呢?

函数与对象的关系

函数 : 处理数据的集合
函数 : 存储数据的集合

数据通过对象来存储 , 通过函数来操作!!!

互为表里 , 不可分割的 好搭档!!!

函数的功能之一就是创建对象 , 返回对象的地址

变量分两类

  1. 存数数据的变量 用var声明
  2. 操作数据的变量 用function声明

这是代码区内存的规则

在stack和heap内存区 , 值的保存和对象的保存是一致的!!!

从代码重构角度理解

刚开始 , 想完成求和的数据操作
var a = 1
var b = 3 
a+b  //求和
每当我们想做求和操作的时候都要重复一次这样的操作 , 太麻烦了
var n1 = 10
var n2 = 15
n1+n2

var n3 = 11
var n4 = 17
n3+n4 
....
//写了很多次太麻烦了
用函数变量进行代码优化
function sum(a,b) {
    this.a = a
    this.b = b
    return a+b
}
sum(10,15)
sum(11,17)
...
//是不是简单很多 , 一次创造 , 多此复用
现在类似于sum()这样的功能函数越来越多 , 并且很多人大量的使用
那么干脆js自己在内存区事前存好这些函数 , 把这些函数放到一个对象中

这就是对象的原型 以及 原型链 构造函数的逐步发展的过程!!!

函数的内存结构

var f = {}
f.params = []
f.fbody = "xxx"
f.call = function() {
    window.eval(f.fbody)
}

浏览器内置对象

内置对象 window
其实就是global 全局对象 , 但是无奈 , ESMC标准在后 , 浏览器实现在先
所以就沿用window对象了

window的属性

常用属性

| ECMAScript规定 | 浏览器私自实现 | | ----------------------- | --------------------- | | parseInt | alert 弹框提示 | | parseFloat | prompt 用户填写 | | Number() | confirm 确认 | | String() | console 开发者 | | Boolean() | document (文档) DOM | | Object() | history (浏览器) BOM | | eval() 执行传入的字符串 | |

Number()为例的基本属性

var n = 1
var n2 = new Number(1)
console.log(n2)  //Number {1}
n 是基本类型的声明
n2 是基本类型的对象包装 , 包含了很多好用的方法 , 最关键的是「长得像java」

程序员都很懒的 , 自然只愿意用第一种 !!!

那么 , 第二种的好用的方法 , 用不到怎么办????

又是 , js语法糖
var n = 1
n.toString()  // 不会报错 , 为什么???
js帮我们做了一层代理
当js引擎看到了 , 上面的代码时 , 
自动做了如下操作:
var temp = new Number(n)
return temp.toString()
n.toString() 实际上是执行的其他代码的返回结果
这个temp临时对象 , 返回值之后就从内存中清除了
var n = 1
n.xxx = "hah"
console.log(n.xxx)  //undefinde

分析:

| 代码区 | stack | heap | | -------- | -------- | ---------------- | | n | 1 | | | temp | ADDR101 | {1} | | http://temp.xxx | ADDR 101 | {1, 'xxx’:’hah’} |

然后 , temp消失了

http://n.xxx 又会触发上述过程 , 可是这一次却没有赋值 , 所以js引擎默认赋值 , undefinde

小结:

  1. 构造函数
  2. 创建临时变量存储对象的地址
  3. 为对象绑定原型
  4. 返回对象的地址
  5. 基本类型的构造函数返回的是对象 , valueof 查值 , toString()转成对象
  6. 基本类型函数对象的原型是是Object()函数对象
  7. 也是我们通常意义上的函数原型链顶点
  8. 所有的对象都是通过构造函数链创建的
与其称之为原型链, 不如称之为构造函数树 , 更能直面问题核心

一个问题: obejct作为对象是谁创建的???

答;Function构造函数创建的

又问 : Function构造函数对象是谁创建的?

答 : 是Fucnction自己

所以一切的源头是一个Function()特例开始的 , 自己创建了自己!!!!!!!!!!!

标准库

ECMA标准规定的 , 必须实现的js对象
  1. Object对象
  2. Array对象
  3. Number()为例的基本类型的包装方法对象
  4. Math对象
  5. RegExp对象
  6. JSON对象
其实就是常用的构造函数而已

对象与New

New是一个语法糖
帮我们做三件事
var temp = {}  // 创建空对象
temp.__proto__ = fun.prototype  //绑定原型
return temp    // 返回对象的地址
Number() 与new
var n = Number(1) // ==>Number()返回的是基本类型
var n2 = new Number(1) // 返回的是对象
Array()与new
var a = new Array(1,2,3)
var a = Array(1,2,3)   //是一样的
function 也是

小结:

  1. 基本类型 用不用new 返回的类型是不一样的
  2. 复杂类型 , 用不用new 返回的类型是一样的
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值