JavaScript题解
1.实现一个方法,使得:add(2, 5) 和 add(2)(5) 的结果都为 7
var add = function (x, r) {
if (arguments.length === 1) {
return function (y) { return x + y; };
} else {
return x + r;
}
};
console.log(add(2)(5)); // 7
console.log(add(2, 5)); // 7
2.alert(1 && 2) 和 alert(1 || 0) 的结果是
alert(1 && 2 ) 的结果是 2
- 只要 "&&" 前面是
false
,无论 "&&" 后面是true
还是false
,结果都将返 "&&" 前面的值 - 只要 "&&" 前面是
true
,无论 "&&" 后面是true
还是false
,结果都将返 "&&" 后面的值
alert(0 || 1) 的结果是 1
- 只要 "||" 前面为
false
,不管 "||" 后面是true
还是false
,都返回 "||" 后面的值 - 只要 "||" 前面为
true
,不管 "||" 后面是true
还是false
,都返回 "||" 前面的值
只要记住 0 与 任何数都是 0,其他反推
3.下面的输出结果是 (考点:作用域、运算符(赋值预算,逗号运算))
var out = 25,
inner = {
out: 20,
func: function () {
var out = 30;
return this.out;
}
};
console.log((inner.func, inner.func)());
console.log(inner.func());
console.log((inner.func)());
console.log((inner.func = inner.func)());
结果:25,20,20,25
先看第一个输出:25,因为 ( inner.func, inner.func
) 是进行逗号运算符,逗号运算符就是运算前面的 ”,“ 返回最后一个,举个栗子:
var i = 0, j = 1, k = 2;
console.log((i++, j++, k)) // 返回的是 k 的值 2 ,如果写成 k++ 的话 这里返回的就是 3
console.log(i); // 1
console.log(j); // 2
console.log(k); // 2
回到原题 ( inner.func, inner.func
) 就是返回 inner.func
,而 inner.func
只是一个匿名函数
function () {
var out = 30;
return this.out;
}
而且这个匿名函数是属于 window
的,则变成了
(function () {
var out = 30;
return this.out;
})()
此刻的 this => window
,所以 out
是 25
第二和第三个 console.log
的作用域都是 inner
,也就是他们执行的其实是 inner.func()
; inner
作用域中是有 out
变量的,所以结果是 20
第四个 console.log 考查的是一个等号运算 inner.func = inner.func ,其实返回的是运算的结果, 举个栗子:
var a = 2, b = 3;
console.log(a = b) // 输出的是 3
所以 inner.func = inner.func
返回的也是一个匿名函数
function () {
var out = 30;
return this.out;
}
此刻,道理就和第一个 console.log
一样了,输出的结果是 25
4.下面程序输出的结果是(考点:变量提升)
if (!("a" in window)) {
var a = 1;
}
alert(a);
代码解析:如果 window
不包含属性 a
,就声明一个变量 a
,然后赋值为 1
在
es6
之前,所有的全局变量都是window
的属性,语句var a = 1
; 等价于window.a = 1
; 你可以用如下方式来检测全局变量是否声明:"变量名称" in window
所有的变量声明都在范围作用域的顶部,看一下相似的例子:
alert("b" in window);
var b;
此时,尽管声明是在 alert
之后,alert
弹出的依然是 true
,这是因为 JavaScript
引擎首先会扫描所有的变量声明,然后将这些变量声明移动到顶部,最终的代码效果是这样的:
var b;
alert("b" in window);
但是,你需要理解该题目的意思是,变量声明被提前了(预编译),但变量赋值没有,因为这行代码包括了变量声明和变量赋值;你可以将语句拆分为如下代码:
var a; //声明
a = 1; //初始化赋值
当变量声明和赋值在一起用的时候,
JavaScript
引擎会自动将它分为两部以便将变量声明提前, 不将赋值的步骤提前,是因为他有可能影响代码执行出不可预期的结果 知道了这些概念以后,重新回头看一下题目的代码,其实就等价于:
var a;
if (!("a" in window)) {
a = 1;
}
alert(a);
题目的意思就非常清楚了:首先声明 a
,然后判断 a
是否在存在,如果不存在就赋值为1,很明显 a
永远在 window
里存在,这个赋值语句永远不会执行,所以结果是 undefined
5.下面程序输出的结果是 (考点:变量函数声明)
var a = 1;
var b = function a(x) {
x && a(--x);
};
alert(a);
结果:1 这里依然有 3 个重要的概念需要我们知道:
- 第一个是变量声明在进入执行上下文就完成了
- 第二个概念就是函数声明也是提前的,所有的函数声明都在执行代码之前都已经完成了声明,和变量声明一样
- 函数声明是如下这样的代码:
function functionName(arg1, arg2){ //函数体 }
- 如下不是函数,而是函数表达式,相当于变量赋值:
var functionName = function(arg1, arg2){ //函数体 }; ``
函数表达式没有提前,就相当于平时的变量赋值
- 第三需要知道的是,函数声明会覆盖变量声明,但不会覆盖变量赋值
举个栗子:
function value(){
return 1;
}
var value;
alert(typeof value); //"function"
尽管变量声明在下面定义,但是变量 value
依然是 function
,也就是说这种情况下,函数声明的优先级高于变量声明的优先级,但如果该变量 value
赋值了,那结果就完全不一样了:
function value(){
return 1;
}
var value = 1;
alert(typeof value); //"number"
该
value
赋值以后,变量赋值初始化就覆盖了函数声明
6.闭包
想每次点击对应目标时弹出对应的数字下标 0~4 ,但实际是无论点击哪个目标都会弹出数字 5
function onMyLoad() {
var arr = document.getElementsByTagName("p");
for (var i = 0; i < arr.length; i++) {
arr[i].onclick = function () {
alert(i);
}
}
}
- 加若干个对应的闭包域空间(这里采用的是匿名函数),专门用来存储原先需要引用的内容(下标),不过只限于基本类型(基本类型值传递,对象类型引用传递)
//声明一个匿名函数,若传进来的是基本类型则为值传递,故不会对实参产生影响,
//该函数对象有一个本地私有变量 arg(形参) ,该函数的 function scope 的 closure 对象属性有两个引用,一个是 arr,一个是 i
//尽管引用 i 的值随外部改变 ,但本地私有变量(形参) arg 不会受影响,其值在一开始被调用的时候就决定了
for (var i = 0; i < arr.length; i++) {
(function (arg) {
arr[i].onclick = function () {
// onclick 函数实例的 function scope 的 closure 对象属性有一个引用 arg,
alert(arg);
//只要 外部空间的 arg 不变,这里的引用值当然不会改变
}
})(i); //立刻执行该匿名函数,传递下标 i (实参)
}
- 将事件绑定在新增的匿名函数返回的函数上,此时绑定的函数中的
function scope
中的closure
对象的 引用arg
是指向将其返回的匿名函数的私有变量arg
for (var i = 0; i < arr.length; i++) {
arr[i].onclick = (function (arg) {
return function () {
alert(arg);
}
})(i);
}
- 使用
ES6
新语法let
关键字
for (var i = 0; i < arr.length; i++) {
let j = i; // 创建一个块级变量
arr[i].onclick = function () {
alert(j);
}
}
7.使用 JavaScript 生成随机数,但不能返回0
function randomFraction() {
var result = 0;
while (result === 0) {
result = Math.random();
}
return result;
}
8.使用箭头函数的语法来计算squaredIntegers数组里正整数的平方(分数不是整数)
const realNumberArray = [4, 5.6, -9.8, 3.14, 42, 6, 8.34];
const squareList = (arr) => {
"use strict";
const squaredIntegers = arr.filter((item) => Math.floor(item) == item).map((item) => item * item)
return squaredIntegers;
};
const squaredIntegers = squareList(realNumberArray);
console.log(squaredIntegers);
9.用JS递归的方式写1到100求和
function sum(n){
if(n==1) return 1;
return sum(n-1) + n;
}
var amount = sum(100);
console.log(amount); // 5050
10.用 JavaScript 写一个函数,输入 int 型,返回整数逆序后的字符串。
如:输入整型 1234,返回字符串“4321”。要求必须使用递归函数调用,不能用全局变量,输入函数必须只有一个参数传入,必须返回字符串。
function test(num) {
var str = num + "";
if (str.length > 1) {
var newStr = str.substring(str.length - 1);
var oldStr = str.substring(0, str.length - 1);
return newStr + test(oldStr);
} else {
return str;
}
}
console.log(test(123));
11.如何把一个字符串的大小写取反(大写变小写小写变大写),例如 ’AbC' 变成 'aBc'
// 方法一:常规
function transformStr(str) {
let tempArr = str.split('')
let result = tempArr.map(char => {
return char === char.toUpperCase() ? char.toLowerCase() : char.toUpperCase()
})
return result.join('')
}
console.log(transformStr('aBc'))
// 方法二:正则
'aBc'.replace(/[A-Za-z]/g, char => char === char.toUpperCase() ? char.toLowerCase() : char.toUpperCase())