1. ['1', '2', '3'].map(parseInt)输出结果
['1', '2', '3'].map(parseInt); // [1,NaN,NaN]
这道题需要理解两个点:
①.parseInt(string, radix)
接收两个参数,第一个表示被处理的值(字符串),第二个表示为解析时的基数。
radix 可选。表示要解析的数字的基数。该值介于 2 ~ 36 之间。如果省略该参数或其值为 0,则数字将以 10 为基础来解析。如果它以 “0x” 或 “0X” 开头,将以 16 为基数。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。
②.代码实际执行的以下代码
['1', '2', '3'].map((item, index) => { return parseInt(item, index) }) parseInt('1', 0) // 1 parseInt('2', 1) // NaN parseInt('3', 2) // NaN, 3 不是二进制 string要符合基数的规范
同样的经典题
['10','10','10','10','10'].map(parseInt) // => parseInt('10', 0) // 10 parseInt('10', 1) // NaN parseInt('10', 2) // 2, parseInt('10', 3) // 3, parseInt('10', 4) // 4, // 所以['10','10','10','10','10'].map(parseInt) => [10,NaN,2,3,4];
2.实现一个函数:输入一个整数,求该整数的二进制表达中有多少个1?
方法1:
function fun1(num){ return new Number(num).toString(2).split('').filter(item => item == 1).length } fun1(9) // 2
方法2:
function fun2(num){ var len = 0; while(num > 0) { var a = num % 2; num = (num - a) / 2; if(a === 1) { len++; } } return len; } fun2(9)
3.实现一个函数:给定一个字符串,找出出现次数最多的字符及次数
function getMaxStr(str) { let json = {}; for(let i =0;i<str.length;i++){ if(json[str[i]]) { json[str[i]]++ }else { json[str[i]] = 1; } } let maxNum = 0; let maxStr = ''; for(let key in json){ if(json[key] > maxNum){ maxNum = json[key]; maxStr = key; } } console.log(`出现次数最多的字符是${maxStr},出现次数是${maxNum}`) } getMaxStr('ddddssfes') // 出现次数最多的字符是d,出现次数是4
4.this指向理解
var a = 1; var obj = { a: 2, func1: ()=>{console.log(this.a)}, func2: function(){console.log(this.a)} } var obj2 = {a: 3}; console.log(obj.func1()) // 1 console.log(obj.func2()) // 2 obj.func2.apply(obj2) // 3 var newFunc = obj.func2; newFunc() //1
tips: 函数直接被调用时this则指向window,函数作为某对象的方法调用时,this指向该对象,而箭头函数没有执行上下文,取决于他就近的外面的一层非箭头函数的函数。
箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window
5.下面三段代码分别输出什么?并且什么时候输出什么?
for (var i = 0; i < 5; i++) { setTimeout(function () { console.log(i) }, 1000 * i) } // 在极短的一段时间内输出5,随后每隔一秒输出一个5 // 5 5 5 5 5
// for循环结束后才到宏观任务setTimeout,这时候i的值已经变为5了
for (let i = 0; i < 5; i++) { setTimeout(function () { console.log(i) }, 1000 * i) } // 在极短的一段时间内输出0,随后每隔一秒结果加1 // 0 1 2 3 4
// let i 是块作用域
for (var i = 0; i < 5; i++) { (function (i) { setTimeout(function () { console.log(i) }, 1000 * i) })(i) } // 在极短的一段时间内输出0,随后每隔一秒结果加1 // 0 1 2 3 4
// 立即执行函数,创建了属于自己的作用域,因此每一次执行都是不同的i
6.自由变量理解
var x = 10 function fn() { console.log(x) } function show(f) { var x = 20 (function() { f() //10,而不是20 })() } show(fn)
什么是自由变量? --当前作用域没有定义的变量,这成为自由变量
var a = 100 function fx() { var b = 200 console.log(a) // 这里的a在这里就是一个自由变量 console.log(b) } fx()
在fn函数中,取自由变量x的值时,要到哪个作用域中取?--要到创建fn函数的那个作用域中取,无论fn函数将在哪里调用。
要到创建这个函数的那个域。作用域中取值,这里强调的是“创建”,而不是“调用”,切记切记——其实这就是所谓的"静态作用域"。
7. 闭包的理解
function outer(){ var num=0;//内部变量 return function add(){//通过return返回add函数,就可以在outer函数外访问了 num++;//内部函数有引用,作为add函数的一部分了 console.log(num); }; } var func1=outer();
func1();//实际上是调用add函数, 输出1 func1();//输出2 因为outer函数内部的私有作用域会一直被占用 var func2=outer(); func2();// 输出1 每次重新引用函数的时候,闭包是全新的。 func2();// 输出2
一般情况下,函数执行会形成一个新的私有的作用域,当私有作用域中的代码执行完成后,我们当前作用域都会主动的进行释放和销毁。但当遇到函数执行返回了一个引用数据类型的值,并且在函数的外面被一个其他的东西给接收了,这种情况下一般形成的私有作用域都不会销毁。
所谓内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。闭包不能滥用,否则会导致内存泄露,影响网页的性能。闭包使用完了后,要立即释放资源,将引用变量指向null。
未完,待续...