-
全局对象 window
ECMAScript 规定全局对象叫做 global,但是浏览器把 window 作为全局对象(浏览器先存在的)
window 就是一个哈希表,有很多属性。
window 的属性就是全局变量。
使用window的属性可以不加window.
,
比如window.alert('警告')
可以写成alert('警告')
这些全局变量分为两种:一种是 ECMAScript 规定的
- global.parseInt
- global.parseFloat
- global.Number
- global.String
- global.Boolean
- global.Object
一种是浏览器自己加的属性
- window.alert
- window.prompt
- window.comfirm
- window.console.log
- window.console.dir
- window.document
// document由浏览器实现,但是也有一个自己的标准,那就是 DOM,它的标准由 W3C 制定 - window.document.createElement
- window.document.getElementById
所有 API 都可以在 MDN 里找到详细的资料。
-
全局函数&简单类型与对象的区别
1. Number()
- MDN
- 阮一峰
Number('1') // 1 强制转换
-
var n = new Number(1) // 返回一个值为1的对象
在这里,Number()对象作为构造函数使用,用来生成值为数值的对象。 - 和直接赋值数字也就是简单类型的区别:
- 一个是简单类型,一个是复杂类型
- 两者对内存的使用不同,假设有
var n1 = 1
var n2 = new Number(1)
内存图: - 包装对象有许多便捷的操作
- 你可以通过
valueOf()
来获得n2
的原始值1
- 其它还有
toString() // 获得字符串形式 toFixed() // 转为指定位数的小数,返回这个小数对应的字符串 toExponential() // 将一个数转为科学计数法形式 toPrecision() // 将一个数转为指定位数的有效数字 (10).toString() // "10" // toString方法可以接受一个参数,表示输出的进制。如果省略这个参数,默认将数值先转为十进制,再输出字符串;否则,就根据参数指定的进制,将一个数字转化成某个进制的字符串。 (10).toString(2) // "1010" (10).toString(8) // "12" (10).toString(16) // "a" // 上面代码中,之所以要把10放在括号里,是为了表明10是一个单独的数值,后面的点表示调用对象属性。如果不加括号,这个点会被JavaScript引擎解释成小数点,从而报错。 // 只要能够让JavaScript引擎不混淆小数点和对象的点运算符,各种写法都能用。除了为10加上括号,还可以在10后面加两个点,JavaScript会把第一个点理解成小数点(即10.0),把第二个点理解成调用对象属性,从而得到正确结果。 10..toString(2) // "1010" // 其他方法还包括 10 .toString(2) // "1010" 10.0.toString(2) // "1010" // toFixed方法用于将一个数转为指定位数的小数,返回这个小数对应的字符串。 (10).toFixed(2) // "10.00" 10.005.toFixed(2) // "10.01" // toExponential方法的参数表示小数点后有效数字的位数,范围为0到20,超出这个范围,会抛出一个RangeError。 (10).toExponential() // "1e+1" (10).toExponential(1) // "1.0e+1" (10).toExponential(2) // "1.00e+1" (1234).toExponential() // "1.234e+3" (1234).toExponential(1) // "1.2e+3" (1234).toExponential(2) // "1.23e+3" // toPrecision方法的参数为有效数字的位数,范围是1到21,超出这个范围会抛出RangeError错误。 (12.34).toPrecision(1) // "1e+1" (12.34).toPrecision(2) // "12" (12.34).toPrecision(3) // "12.3" (12.34).toPrecision(4) // "12.34" (12.34).toPrecision(5) // "12.340"
- 两种赋值方式的历史:
var n = new Number(1)
是当初被要求要像java才做出来的方式,实际上更受人喜欢的依然是var n = 1
,
但是这样方式无法使用Number对象的方法怎么办,于是又有了下面的东西; - 基本包装类型
理论上基本类型是不能没有toString()
之类的方法的,然而实际上却可以使用,
这是因为每当地区一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据,如下:
也因此,var n = 1 // 1 var s = n.toString() // '1' // 后台自动操作 var temp = new Number(n) // 创建一个 Number 类型的实例 temp.toString() // 调用指定方法 // 然后将temp.toString()的值作为n.toString()的值 // 最后销毁temp,释放空间 // 所以这是一种临时的转换,基本类型实际上并没有属性,
var n = new Number(1)
这种方式基本不再被大家所使用 - 思考题
var n = 1 n.xxx = 2 // 问:是否会报错? // NO! n.xxx = 2 // 2 n.xxx // undefined
解析:n.xxx = 2这段代码执行时新建了一个临时变量temp以及属性xxx储存值2,所以不会报错,
但是执行 n.xxx 的时候浏览器显示的却是 undefined,这是因为 temp 是临时创建出来了,使用后会立即销毁,执行 n.xxx 的时候上一句代码创建的临时temp已经被销毁了,这时候又是一个新的temp,它并没有xxx这个属性以及值
- String()和Boolean()也是同理
- 阮一峰
- JavaScript高级程序设计第五章-5.6-基本包装类型
2. String()
- MDN
- MDN学习教程
- 阮一峰
var s = 'abc' var s2 = new String(s) // charAt方法返回指定位置的字符,参数是从0开始编号的位置。 s.charAt(1) // "b" s.charAt(s.length - 1) // "c" // 这个方法完全可以用数组下标替代。 'abc'.charAt(1) // "b" 'abc'[1] // "b" // 如果参数为负数,或大于等于字符串的长度,charAt返回空字符串。 'abc'.charAt(-1) // "" 'abc'.charAt(3) // "" // charCodeAt方法返回给定位置字符的Unicode码点(十进制表示),相当于String.fromCharCode()的逆操作。 'abc'.charCodeAt(1) // 98 // 如果没有任何参数,charCodeAt返回首字符的Unicode码点。 'abc'.charCodeAt() // 97 // 如何返回 16 进制表示的Unicode码点 'abc'.charCodeAt(0).toString(16) // trim方法用于去除字符串两端的空格,返回一个新字符串,不改变原字符串。 ' hello world '.trim() // "hello world" // 该方法去除的不仅是空格,还包括制表符(\t、\v)、换行符(\n)和回车符(\r)。 '\r\nabc \t'.trim() // 'abc' // concat方法用于连接两个字符串,返回一个新字符串,不改变原字符串。 var s1 = 'abc'; var s2 = 'def'; s1.concat(s2) // "abcdef" s1 // "abc" s2 // "def" // 该方法可以接受多个参数。 'a'.concat('b', 'c') // "abc" // slice方法用于从原字符串取出子字符串并返回,不改变原字符串。 // 它的第一个参数是子字符串的开始位置,第二个参数是子字符串的结束位置(不含该位置)。 'JavaScript'.slice(0, 4) // "Java" // 如果省略第二个参数,则表示子字符串一直到原字符串结束。 'JavaScript'.slice(4) // "Script" // 如果参数是负值,表示从结尾开始倒数计算的位置,即该负值加上字符串长度。 'JavaScript'.slice(-6) // "Script" 'JavaScript'.slice(0, -6) // "Java" 'JavaScript'.slice(-2, -1) // "p" // 如果第一个参数大于第二个参数,slice方法返回一个空字符串。 'JavaScript'.slice(2, 1) // ""
- String()有很多api,这里只写了几个常用的,更多详见上面两个链接
3. Boolean()
- MDN
- 阮一峰
var b = new Boolean(true) b.toString() // 'true' b.valueOf() // true // 踩坑 var f = false var f2 = new Boolean(false) if(f) { console.log(1) } if(f2) { console.log(2) } // 问:会打印出什么? 2 // 只打印 2,因为 f2 并不是 false,因为它是一个对象,而对象是 true // 别忘记js中只有 NAN、null、undefined、''、0是false,而对象和其它的都是true
4. Object()
-
公共属性(原型)
var n = new Numer(1) var s = new String('a') var b = new Boolean(true) var o = new Object() // 上面4个不同的对象都有`toString()、valueOf()`属性,可是如果每个对象都创建2个属性会很浪费内存, // 所以,共用就好了
那么怎么访问公共属性呢?每个对象的toString储存公共属性的toString的地址?不
-
proto
js通过隐藏属性__proto__
属性来访问公共属性,它指向了那些所有对象共有的属性
步骤:- 首先查看自身是否是对象,如果不是就包装对象
- 如果是对象就查看自身的 key 有没有 toString,有的话就直接调用
- 如果没有的话就通过
__proto__
查看你的共用属性看有没有,有的话就将你自身对应的值打印出来
例子:
var o1 = {name: 'zero'} o1.toString() // [object Object] // 依照步骤来,o1是对象,o1没有toString,查看共有属性,有toString,打印o1对应的值 // 不仅仅是o1,创建更多的对象也是一样,所有的对象都有隐藏属性`__proto__`,指向对应的共有属性 var o2 = {} o1 === o2 // false o1.toString() === o2.toString() // true
- 如果是Number对象呢?
var n = new Number(11) n.toString(16) // numer对象可以这样,而oject对象是不能这样toString(16)的
可以看见,Number重写了toString属性,以及添加一部分自己的属性,
然后通过__proto__
指向Object,对象共有属性
所以如同上图,Number对象就是在第3步去Number重写的属性寻找,没有的话去共有属性找
Number对象的__proto__
指向Number重写的共有属性,Number重写的共有属性的__proto__
指向对象共有属性 -
除了Number以外,类似的还有String、Boolean(目前所学的)
- 原型链
对象的属性和方法,有可能定义在自身,也有可能定义在它的原型对象。由于原型本身也是对象,又有自己的原型,所以形成了一条原型链(prototype chain),就像我们上面画的图一样,
-
如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。Object.prototype 就是 Object对象的共有属性,相对的,Number.prototype就是Number对象的共有属性,而Number.prototype的proto又指向Object.prototype,也就是它的共有属性,String和Boolean也是如此
看这张图,结合前面所学的数据结构,是不是很有意思,
根节点是Object.prototype,三个子节点分别是String.prototype、Number.prototype、Boolean.prototype,
当你执行var str = new String('a')
时,浏览器就会在堆中创建一个hash,str保存这个hash的地址,
这个hash也就是String对象中除了你定义的属性外还有隐藏属性proto指向String.prototype,String.prototype又指向Object.prototype,这就完成了String API的所有绑定,
Number和Boolean也是一样 “原型链”的作用是,读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。
如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding)。
需要注意的是,一级级向上,在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
-
prototype与proto
两者都指向共用属性
String.prototype 是 String 的共用属性的引用(防止共用属性被垃圾回收)
s.proto 是 String 的共用属性的引用(这是你在用共用属性)
proto 是对象的属性,prototype 是函数的属性
它们储存的地址相同,指向的其实是同一个对象// 一些烧脑的东西 var obj1 = 函数.prototype obj1.__proto__ === Object.prototype // 等于下面 函数.prototype.__proto__ === Object.prototype var obj2 = 函数 obj2.__proto__ === Function.prototype // 也就是 函数.__proto__ === Function.prototype Function.__proto__ === Function.prototype Function.prototype.__proto__ === Obeject.prototype String.__proto__ === Function.prototype Number.__proto__ === Function.prototype Boolean.__proto__ === Function.prototype Object.__proto__ === Function.prototype
总之,记住公式:
对象.__proto__ === 函数.prototype
函数.__proto__ === Function.prototype
参考 那么,Object.prototype对象有没有它的原型呢?回答是有的,就是没有任何属性和方法的null对象,而null对象没有自己的原型。
Object.getPrototypeOf(Object.prototype) // null
上面代码表示,Object.prototype对象的原型是null,由于null没有任何属性,所以原型链到此为止。
Object.prototype 就是 Object对象的共有属性
-
proto
A22-JS里的对象
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- 序 从最近的js入门系列的阅读量逐步递减,观众老爷的兴趣也不再能够接受一些细节性的地方深度挖掘,让我有了一些思考。...
- 为丰富大学生暑期三下乡文化生活,展示学生践行“中国梦”的青春风采,简书现举办“感悟三下乡 青春筑梦行”暑期社会实践...