对象,原型与原型链
全局对象
ECMAScript 规定全局对象叫做 global,但是浏览器把 window 作为全局对象(浏览器先存在的)
window 就是一个哈希表,有很多属性。
window 的属性就是全局变量。
在浏览器下, window 的属性可以分为两类:
- ECMAScript 规定的,例如
parseInt()
,parseFloat()
,Number()
,String()
,Boolean()
,setTimeout()
等等 - 浏览器私有属性,例如
alert
弹框提示 ,propmt
用户填写 ,confirm
确认,console
等,document
也是。 DOM也有标准,由 W3C 制定。
Number()
Number() 有两种用法:
- Number(xxx) 用来把 xxx 转换为数字
声明一个 number 对象,包装成对象,有很多便捷的操作可以用
var n = new Number(1) n.valueOf() // 1 n.toString() // "1" n.toFixed(3) // "1.000" n.toExponential() "1e+0"
但是在 Javascript 中,我们很少用第二种方法。
你有没有想过,为什么 var a = 1
仅仅是声明了一个基本类型,基本类型没有属性,但是却有很多操作可以直接用呢?
var a = 1
a.toFixed(3)
// "1.000"
a.toString()
// "1"
a.valueOf()
// 1
原因在于这其中涉及到了临时转换。
在声明的时候,JavaScript 创建了临时对象,上面记录了一些可以使用的操作,在语句结束之后,临时对象会消失。
var b = 1
b.xxx = 2 //看到 b ,JS马上创建了临时对象,语句结束后,临时对象消失
b.xxx //此时又看到b,JS马上创建了新的临时对象。。
// undefined
看下面的内存图:
var n=1;
n.toString() ==> temp=new Number(n);
temp.toString() //用完后把temp对象干掉
String()
- String(xxx) 用来把 xxx 转换为字符串
声明一个 string 对象,有很多便捷的操作可以用
var s = 'Jonathan' var s2 = new String('Hello!')
建议在 Chrome 控制台输入观察一下。
charAt() 和 charCodeAt()
var s = 'Jonathan'
var s2 = new String('Hello!')
s2.charAt(0) //返回某个索引对应的字符
// "H"
s2.charCodeAt(0) //返回某个索引对应的字符的 unicode 编码
// 72
'a'.charCodeAt()
// 97
'a'.charCodeAt(0)
// 97
'a'.charCodeAt().toString(16)
// "61" //a的十六进制的 unicode 是 "61"
string 还有很多很多 API:
- trim()
- concat()
- slice()
- replace()
- ……
Boolean()
- Boolean(xxx)
声明一个 Boolean 对象,有很多便捷的操作可以用
var f = false var f2 = new Boolean(false) if (f) {console.log(1)} if (f2) {console.log(2)} // 2
Object()
不同于基本类型,Object 这两种声明方法没有区别。但是需要注意,这两者并不相等。
var o = {}
var o2 = new Object() // 不常用
o === o2
// false
公用的属性
- 避免浪费内存
- 当声明一个对象时,生成一个隐藏的key
__proto__
,其 value 指向公用属性。
所有对象都有 toString 和 valueOf 属性,那么我们是否有必要给每个对象一个 toString 和 valueOf 呢?
明显不需要。
JS 的做法是把 toString 和 valueOf 放在一个对象里(暂且叫做公用属性组成的对象)
然后让每一个对象的
__proto__
存储这个「公用属性组成的对象」的地址。
重要公式
var 对象 = new 函数()
对象.__proto__ === 函数.prototype
请记住并疯狂思考下面这张图
不妨大胆地思考一下:
// 声明一个对象 obj ,它有自己的属性 name 和 toString:
var obj = {
name: 'Jonathan',
toString: function() {
return '666'
}
}
// obj 的原型 obj.__proto__ 有很多属性,比如:toString 和 valueOf
// 最后,obj.__proto__.__proto__ 是 null
// 这就是原型链的末尾,即 null
// null 没有 __proto__
// 综上,整个原型链如下:
// obj ---> obj.__proto__ ---> null
console.log(obj.name) // Jonathan
// name 是 obj 自身的属性,值为 Jonathan
console.log(obj.toString) // f() { return '666'}
// toString 是 obj 自身的属性
// obj.__proto__ 上还有一个 toString 属性,但是不会被访问到。
// 这种情况称为 属性遮蔽(property shadowing)
console.log(obj.valueOf) // ƒ valueOf() { [native code] }
// valueOf 并非 obj 自身的属性,那就继续找找 obj.__proto__
console.log(obj.xxx) // undefined
// xxx 是 obj 的自身属性吗?不是,那看看 o.__proto__ 上有没有
// xxx 是 o.__proto__ 的自身属性吗?不是,那看看 o.__proto__.__proto__ 上有没有
// o.__proto__.__proto__为null,停止搜索
// 没有 xxx 属性,返回 undefined
学习资料:
(完)