js知识点记录

111 阅读6分钟

1, let data = { count:'' } let res = data.count *1; console.log(res) res为0 2 转为Number res = +a; 3 console.log(4 in [2,4,6]) false. in,遍历的包括prototype的属性名。而2,4,6,对应的是0,1,2, 4 toPrecision()和toFixed()方法 的返回值字符串 5 parseInt(011, 2) // NaN 第一行的011会被先转为字符串9,因为9不是二进制的有效字符,所以返回NaN。 parseInt('011', 2), 011则是会被当作二进制处理,返回3 6 ~ 为2的补码 ~x 大致等同于 -(x+1) 如 ~42 = -(42 + 1)= -43 7 在 -(x+1) 中唯一能够得到 0(或者严格说是 -0)的 x 值是 -1。-1 是一个“哨位值” 如 ~a.indexOf( "lo" ); 判断是否存在。 8 ~~x 能将值截除为一个 32 位整数, x | 0 也可以,而且看起来还更简洁。 9 [] == ![] true 文首提出的 [] == ![] 这个比较运算,首先 [] 为对象,则调用 ToPrimitive 函数将其转化为字符串 "";对于右侧的 ![],首先会进行显式类型转换,将其转化为 false。然后在比较运算中,会将运算符两侧的运算对象都转化为数值类型,即都转化为了 0,

10  	"2" == true   为 flase
11 	null == 0 // false         左面是字符串右面是数值就会被转化而null 为基本类型
		null >= 0 // true           null 转为number为0;
12  	let obj = {};

{} + 1 // 1,这里的 {} 被当成了代码块 { 1 + 1 } + 1 // 1 13对于数值类型的 valueOf() 函数的调用结果仍为数组,因此数组类型的隐式类型转换结果是字符串。

[2,3] + [1,2] // '2,31,2' // 减法或其他操作,无法进行字符串连接,因此在错误的字符串格式下返回 NaN [2,3] - 1 // NaN 14 new Boolean({}) 为 true 15 var a = null; var b = Object( a ); // 和Object()一样 a == b; // false var c = undefined; var d = Object( c ); // 和Object()一样 c == d; // false var e = NaN; var f = Object( e ); // 和new Number( e )一样 e == f; // false 因为没有对应的封装对象,所以 null 和 undefined 不能够被封装(boxed), Object(null) 和 Object() 均返回一个常规对象 NaN 能够被封装为数字封装对象,但拆封之后 NaN == NaN 返回 false 16 var a = { b: 42 }; var b = { b: 43 }; a < b; // false a == b; // false a > b; // false a <= b; // true a >= b; // true

根据规范 a <= b 被处理为 b < a,然后将结果反转。处理为 !(b < a) 17 [] + {}; // "[object Object]" {} + []; // 0 18 var b = 10; (function b(){ b = 20; console.log(b); })(); 19,简单改造下面的代码,使之分别打印 10 和 20。

var b = 10; (function b(){ b = 20; console.log(b); })(); 答案:var b = 10; (function b(b) { b = 20; console.log(b) })(b) 20 var a = 10; (function () { console.log(a) a = 5 console.log(window.a) var a = 20; console.log(a) })() 答案undefined,10,20。 21 使用 sort() 对数组 [3, 15, 8, 29, 102, 22] 进行排序,输出结果 22 var obj = { '2': 3, '3': 4, 'length': 2, 'splice': Array.prototype.splice, 'push': Array.prototype.push } obj.push(1) obj.push(2) console.log(obj) 答案:var obj = { '2': 3, '3': 4, 'length': 2, 'splice': Array.prototype.splice, 'push': Array.prototype.push } obj.push(1) obj.push(2) console.log(obj) 结果:[,,1,2], length为4 21 function Foo() { Foo.a = function() { console.log(1) } this.a = function() { console.log(2) } } Foo.prototype.a = function() { console.log(3) } Foo.a = function() { console.log(4) } Foo.a(); let obj = new Foo(); obj.a(); Foo.a(); 答案 输出顺序是 4 2 1 .

function Foo() { Foo.a = function() { console.log(1) } this.a = function() { console.log(2) } } // 以上只是 Foo 的构建方法,没有产生实例,此刻也没有执行

Foo.prototype.a = function() { console.log(3) } // 现在在 Foo 上挂载了原型方法 a ,方法输出值为 3

Foo.a = function() { console.log(4) } // 现在在 Foo 上挂载了直接方法 a ,输出值为 4

Foo.a(); // 立刻执行了 Foo 上的 a 方法,也就是刚刚定义的,所以 // # 输出 4

let obj = new Foo(); /* 这里调用了 Foo 的构建方法。Foo 的构建方法主要做了两件事:

  1. 将全局的 Foo 上的直接方法 a 替换为一个输出 1 的方法。
  2. 在新对象上挂载直接方法 a ,输出值为 2。 */

obj.a(); // 因为有直接方法 a ,不需要去访问原型链,所以使用的是构建方法里所定义的 this.a, // # 输出 2

Foo.a(); // 构建方法里已经替换了全局 Foo 上的 a 方法,所以 // # 输出 1 22 function changeObjProperty(o) { o.siteUrl = "www.baidu.com" o = new Object() o.siteUrl = "www.google.com" } let webSite = new Object(); changeObjProperty(webSite); console.log(webSite.siteUrl); 答案 // 这里把o改成a // webSite引用地址的值copy给a了 function changeObjProperty(a) { // 改变对应地址内的对象属性值 a.siteUrl = "www.baidu.com" // 变量a指向新的地址 以后的变动和旧地址无关 a = new Object() a.siteUrl = "www.google.com" a.name = 456 } var webSite = new Object(); webSite.name = '123' changeObjProperty(webSite); console.log(webSite); // {name: 123, siteUrl: 'www.baidu.com'} 23 const data = [{ id: '1', name: 'test1', children: [ { id: '11', name: 'test11', children: [ { id: '111', name: 'test111' }, { id: '112', name: 'test112' } ]

    },
    {
        id: '12',
        name: 'test12',
        children: [
            {
                id: '121',
                name: 'test121'
            },
            {
                id: '122',
                name: 'test122'
            }
        ]
    }
]

}]; 输出所有父级 答案 const fn = (data, value) => { let res = [] const dfs = (arr, temp = []) => { for (const node of arr) { if (node.children) { dfs(node.children, temp.concat(node.id)) } else { if (node.id === value) { res = temp } return } } } dfs(data) return res } 24 // 原始 list 如下 let list =[ {id:1,name:'部门A',parentId:0}, {id:2,name:'部门B',parentId:0}, {id:3,name:'部门C',parentId:1}, {id:4,name:'部门D',parentId:1}, {id:5,name:'部门E',parentId:2}, {id:6,name:'部门F',parentId:3}, {id:7,name:'部门G',parentId:2}, {id:8,name:'部门H',parentId:4} ]; const result = convert(list, ...);

// 转换后的结果如下 let result = [ { id: 1, name: '部门A', parentId: 0, children: [ { id: 3, name: '部门C', parentId: 1, children: [ { id: 6, name: '部门F', parentId: 3 }, { id: 16, name: '部门L', parentId: 3 } ] }, { id: 4, name: '部门D', parentId: 1, children: [ { id: 8, name: '部门H', parentId: 4 } ] } ] }, ··· ]; 答案 function convert(list) { const res = [] const map = list.reduce((res, v) => (res[v.id] = v, res), {}) for (const item of list) { if (item.parentId === 0) { res.push(item) continue } if (item.parentId in map) { const parent = map[item.parentId] parent.children = parent.children || [] parent.children.push(item) } } return res } 时间复杂度O(n) 25 var a = {n: 1}; var b = a; a.x = a = {n: 2};

console.log(a.x) console.log(b.x) 答案 undefined {n:2}

首先,a和b同时引用了{n:2}对象,接着执行到a.x = a = {n:2}语句,尽管赋值是从右到左的没错,但是.的优先级比=要高,所以这里首先执行a.x,相当于为a(或者b)所指向的{n:1}对象新增了一个属性x,即此时对象将变为{n:1;x:undefined}。之后按正常情况,从右到左进行赋值,此时执行a ={n:2}的时候,a的引用改变,指向了新对象{n:2},而b依然指向的是旧对象。之后执行a.x = {n:2}的时候,并不会重新解析一遍a,而是沿用最初解析a.x时候的a,也即旧对象,故此时旧对象的x的值为{n:2},旧对象为 {n:1;x:{n:2}},它被b引用着。 后面输出a.x的时候,又要解析a了,此时的a是指向新对象的a,而这个新对象是没有x属性的,故访问时输出undefined;而访问b.x的时候,将输出旧对象的x的值,即{n:2}。