function f() {}
var a = f.prototype;
var b = Object.getPrototypeOf(f);
a === b;
// 通过一个例子简单解释下
function Person() {}
var p = new Person();
var a = p.__proto__;
var b = Object.getPrototypeOf(p);
var c = Person.prototype;
console.log(a === b, a === c, b === c);
// true, true, true
var d = Person.__proto__;
var e = Object.getPrototypeOf(Person);
var f = Function.prototype;
console.log(d === e, d === f, e === f);
// true, true, true
A:false
R:任何函数都是 Function 的实例,而p是函数 Person 的实例,Object.getPrototypeOf 会获取构造当前对象的原型。所以 Object.getPrototypeOf(p) === Person.prototype,而 Object.getPrototypeOf(Person) === Function.prototype
禁止修改函数名
function foo() {}
var oldName = foo.name;
foo.name = "bar";
[oldName, foo.name];
var a = Date(0);
var b = new Date(0);
var c = new Date();
[a === b, b === c, a === c];
A: [false, false, false]
R:只能通过调用 Date 构造函数来实例化日期对象:以常规函数调用它(即不加 new 操作符)将会返回一个字符串,而不是一个日期对象。另外,不像其他JavaScript 类型,Date 对象没有字面量格式。所以a是字符串,b和c是Date对象,并且b代表的是1970年那个初始化时间,而c代表的是当前时间。
min与max共舞
var min = Math.min();
var max = Math.max();
console.log(min < max);
愤怒的 reduce
A:error
R:如果数组为空并且没有提供initialValue, 会抛出TypeError 。如果数组仅有一个元素(无论位置如何)并且没有提供initialValue, 或者有提供initialValue但是数组为空,那么此唯一值将被返回并且callback不会被执行。
该死的优先级
A:Something
R:因为 + 的优先级比条件运算符 condition ? val1 : val2 的优先级高。
死循环陷阱
A:发生死循环
R:在JavaScript中,2^53 是最大的值,没有比这更大的值了。所以 2^53 + 1 == 2^53,所以这个循环无法终止。
过滤器魔法
A:[]
R:filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或 等价于 true 的值 的元素创建一个新数组。callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中。
警惕IEEE 754标准
A:[true, false]
R:JavaScript中采用双精度浮点数格式,即IEEE 754标准。在该格式下,有些数字无法表示出来,比如:0.1 + 0.2 = 0.30000000000000004 ,这不是JavaScript的锅,所有采用该标准的语言都有这个问题
并非都是奇偶
A:[true, true, true, false, false]
R:-9 % 2 = -1 以及 Infinity % 2 = NaN,求余运算符会保留符号,所以只有 isEven 的判断是可靠的。
parseInt小贼
A:3,NaN,3
R: parseInt 函数只需要两个参数 parseInt(value, radix) ,而 map 的回调函数需要三个参数 callback(currentValue, index, array)。MDN文档中指明 parseInt 第二个参数是一个2到36之间的整数值,用于指定转换中采用的基数。如果省略该参数或其值为0,则数字将以10为基础来解析。如果该参数小于2或者大于36,则 parseInt 返回 NaN。此外,转换失败也会返回 NaN。
数组原型是数组
A:true
R:一个鲜为人知的事实:其实 Array.prototype 也是一个数组。
一言难尽的强制转换
A:false
R:当 [0] 需要被强制转成 Boolean 的时候会被认为是 true。所以进入第一个 if 语句,== 相等中,如果有一个操作数是布尔类型,会先把他转成数字,所以比较变成了 [0] == 1;同时规范指出如果其他类型和数字比较,会尝试把这个类型转成数字再进行宽松比较,而对象(数组也是对象)会先调用它的 toString() 方法,此时 [0] 会变成 "0",然后将字符串 "0" 转成数字 0,而 0 == 1 的结果显然是 false。
打死那个疯子
A:2
R:可以在符号之间插入 0 来理解,即 1 + 0 - 0 + 0 + 0 + 0 - 0 + 1
统统算我的
A:21
R:在JavaScript中,参数变量和 arguments 是双向绑定的。改变参数变量,arguments 中的值会立即改变;而改变 arguments 中的值,参数变量也会对应改变。
反转世界
A:window
R:reverse 方法颠倒数组中元素的位置,并返回该数组的引用。而这里调用的时候没有制定数组,所以默认的 this 就是 window,所以最后结果返回的是 window。
最小的正值
A:true
R:MIN_VALUE属性是 JavaScript 里最接近 0 的正值,而不是最小的负值。
谨记优先级
A:[true, true]
R:<和>的优先级都是从左到右,所以 1 < 2 < 3 会先比较 1 < 2,这会得到 true,但是 < 要求比较的两边都是数字,所以会发生隐式强制转换,将 true 转换成 1,所以最后就变成了比较 1 < 3,结果显然为 true。同理可以分析后者。
坑爹中的战斗机
A:true
R:如果比较的两个值中有一个是数字类型,就会尝试将另外一个值强制转换成数字,再进行比较。而数组强制转换成数字的过程会先调用它的 toString方法转成字符串,然后再转成数字。所以 [2]会被转成 "2",然后递归调用,最终 [[[2]]] 会被转成数字 2。
小数点魔术
A:error, "3", error
R:点运算符会被优先识别为数字常量的一部分,然后才是对象属性访问符。所以 3.toString() 实际上被JS引擎解析成 (3.)toString(),显然会出现语法错误。但是如果你这么写 (3).toString(),人为加上括号,这就是合法的。
自动提升为全局变量
A:1, error
R:在函数中没有用 var 声明变量 y,所以 y 会被自动创建在全局变量 window下面,所以在函数外面也可以访问得到。而 x 由于被 var 声明过,所以在函数外部是无法访问的。
正则表达式实例
A:false, false
R:每个字面的正则表达式都是一个单独的实例,即使它们的内容相同。
数组也爱比大小
A:false, false, false, true
R:数组也是对象,ES5规范指出如果两个对象进行相等比较,只有在它们指向同一个对象的情况下才会返回 true,其他情况都返回 false。而对象进行大小比较,会调用 toString 方法转成字符串进行比较,所以结果就变成了字符串 "1,2,3" 和 "1,2,4" 按照字典序进行比较了
原型把戏
A:[false, true]
R:对象是没有 prototype 属性的,所以 a.prototype 是 undefined,但我们可以通过 Object.getPrototypeOf 方法来获取一个对象的原型。
构造函数的函数
A:false
R:任何函数都是 Function 的实例,而p是函数 Person 的实例,Object.getPrototypeOf 会获取构造当前对象的原型。所以 Object.getPrototypeOf(p) === Person.prototype,而 Object.getPrototypeOf(Person) === Function.prototype
禁止修改函数名
A:["foo", "foo"]
R:函数名是禁止修改的,规范写的很清楚,所以这里的修改无效。
替换陷阱
A:"1 NaN 3"
R:如果 replace 方法第二个参数是一个函数,则会在匹配的时候多次调用,第一个参数是匹配的字符串,第二个参数是匹配字符串的下标。所以变成了调用 parseInt(1, 0)、parseInt(2, 2)和parseInt(3, 4),结果你就懂了。
Function的名字
A:"f", "Empty", "function", "function"
R:代码中的 parent 实际上就是 Function.prototype,输出为
它的 name 属性是 "",所以你 eval("")是得不到任何东西的。
正则测试陷阱
A:[true, true]
R:test 方法的参数如果不是字符串,会经过抽象 ToString操作强制转成字符串,因此实际上测试的是字符串 "null" 和 "undefined"
逗号定义数组
A:", , "
R:JavaScript允许用逗号来定义数组,得到的数组是含有3个 undefined 值的数组。所有的数组元素被转换成字符串,再用一个分隔符将这些字符串连接起来。如果元素是undefined 或者null, 则会转化成空字符串。
保留字 class
R:实际上真正的答案取决于浏览器。class 是保留字,但是在Chrome、Firefox和Opera中可以作为属性名称,在IE中是禁止的。另一方面,其实所有浏览器基本接受大部分的关键字(如:int、private、throws等)作为变量名,而class是禁止的。
无效日期
A:Invalid Date
R:它实际上是一个Date对象,因为 a instance Date 的结果是 true,但是它是无效的Date。Date对象内部是用一个数字来存储时间的,在这个例子中,这个数字是 NaN。
神鬼莫测的函数长度
A:实际上a的值是1,b的值是0。
R:Function 构造器本身也是个Function。他的 length 属性值为 1 。该属性 Writable: false, Enumerable: false, Configurable: true。Function原型对象的 length 属性值为 0 。所以,a 是构造器属性,b 是 Function 原型属性
Date的面具
A: [false, false, false]
R:只能通过调用 Date 构造函数来实例化日期对象:以常规函数调用它(即不加 new 操作符)将会返回一个字符串,而不是一个日期对象。另外,不像其他JavaScript 类型,Date 对象没有字面量格式。所以a是字符串,b和c是Date对象,并且b代表的是1970年那个初始化时间,而c代表的是当前时间。
min与max共舞
A:false
R:对 Math.min 来说,如果没有参数,结果为Infinity,对 Math.max 来说,如果没有参数,结果为-Infinity。
警惕全局匹配
A:[true, false]
R:当正则表达式使用 "g" 标志时,可以多次执行 exec 方法来查找同一个字符串中的成功匹配。当你这样做时,查找将从正则表达式的 lastIndex 属性指定的位置开始。
最熟悉的陌生人
A:[false, false]
R:当Date作为构造函数调用并传入多个参数时,如果数值大于合理范围时(如月份为13或者分钟数为70),相邻的数值会被调整。比如 new Date(2013, 13, 1)等于new Date(2014, 1, 1),它们都表示日期2014-02-01(注意月份是从0开始的)。其他数值也是类似,new Date(2013, 2, 1, 0, 70)等于new Date(2013, 2, 1, 1, 10),都表示时间2013-03-01T01:10:00。此外,getDay 返回指定日期对象的星期中的第几天(0~6)。
匹配隐式转换
A:["hello", "bye"]
R:一个变量在同一作用域中已经声明过,会自动移除 var 声明,但是赋值操作依旧保留,同名变量忽略原则,后声明被忽略。