将此方法添加至 Array.prototype 实现,代码以下:javascript
Array.prototype.duplicator = function(){ var l = this.length,i; for(i=0;i<l;i++){ this.push(this[i]) } }
for (var i = 1; i <= 30; i++) { if (i % 3 === 0) { if (i % 5 === 0) { alert('fizzbuzz' + i); continue; } alert('fizz' + i); continue; } else if (i % 5 === 0) { if (i % 3 === 0) { alert('fizzbuzz' + i); continue; } alert('buzz' + i); continue; } }
(function(){ var a = b = 3; })(); console.log("a defined? " + (typeof a !== 'undefined')); console.log("b defined? " + (typeof b !== 'undefined'));
输出: a defined? false b defined? truehtml
function foo1(){ return { bar: "hello" }; }function foo2(){ return { bar: "hello" }; }
返回不相同: foo1 returns:Object {bar: "hello"}foo2 returns:undefined前端
分号在JavaScript中是一个可选项(尽管省略它们一般是很是糟糕的形式)。其结果就是,当碰到 foo2()中包含 return语句的代码行(代码行上没有其余任何代码),分号会当即自动插入到返回语句以后。也不会抛出错误,由于代码的其他部分是彻底有效的,即便它没有获得调用或作任何事情(至关于它就是是一个未使用的代码块,定义了等同于字符串 "hello"的属性 bar)。java
这种行为也支持放置左括号于JavaScript代码行的末尾,而不是新代码行开头的约定。正如这里所示,这不只仅只是JavaScript中的一个风格偏好。算法
console.log(0.1 + 0.2);console.log(0.1 + 0.2 == 0.3);
JavaScript中的数字和浮点精度的处理相同,所以,可能不会老是产生预期的结果。
以上所提供的例子就是一个演示了这个问题的典型例子。但出人意料的是,它会输出:
0.30000000000000004false跨域
(function() { console.log(1); setTimeout(function(){console.log(2)}, 1000); setTimeout(function(){console.log(3)}, 0); console.log(4); })();
序号以下:
1 4 3 2数组
比较明显而易见的那部分:
1 和 4之因此放在前面,是由于它们是经过简单调用 console.log() 而没有任何延迟输出的
2 之因此放在 3的后面,是由于 2 是延迟了1000毫秒(即,1秒)以后输出的,而 3 是延迟了0毫秒以后输出的。
好的。可是,既然 3 是0毫秒延迟以后输出的,那么是否意味着它是当即输出的呢?若是是的话,那么它是否是应该在 4 以前输出,既然 4 是在第二行输出的?
要回答这个问题,你须要正确理解JavaScript的事件和时间设置。
浏览器有一个事件循环,会检查事件队列和处理未完成的事件。例如,若是时间发生在后台(例如,脚本的 onload 事件)时,浏览器正忙(例如,处理一个 onclick),那么事件会添加到队列中。当onclick处理程序完成后,检查队列,而后处理该事件(例如,执行 onload 脚本)。
一样的, setTimeout() 也会把其引用的函数的执行放到事件队列中,若是浏览器正忙的话。
当setTimeout()的第二个参数为0的时候,它的意思是“尽快”执行指定的函数。具体而言,函数的执行会放置在事件队列的下一个计时器开始。可是请注意,这不是当即执行:函数不会被执行除非下一个计时器开始。这就是为何在上述的例子中,调用 console.log(4) 发生在调用 console.log(3) 以前(由于调用 console.log(3) 是经过setTimeout被调用的,所以会稍微延迟)。浏览器
下面这个函数在 str 是回文结构的时候返回true,不然,返回false。闭包
function isPalindrome(str) { str = str.replace(/\W/g, '').toLowerCase(); return (str == str.split('').reverse().join('')); }
例如:app
console.log(isPalindrome("level")); // logs 'true'console.log(isPalindrome("levels")); // logs 'false'console.log(isPalindrome("A car, a man, a maraca")); // logs 'true'
console.log(sum(2,3)); // Outputs 5 console.log(sum(2)(3)); // Outputs 5
(至少)有两种方法能够作到:
方法1:
function sum(x) { if (arguments.length == 2) { return arguments[0] + arguments[1]; }else { return function(y) { return x + y; }; } }
方法2:
function sum(x, y) { if (y !== undefined) { return x + y; } else { return function(y) { return x + y; }; } }
for (var i = 0; i < 5; i++) { var btn = document.createElement('button'); btn.appendChild(document.createTextNode('Button ' + i)); btn.addEventListener('click', function(){ console.log(i); }); document.body.appendChild(btn); }
(a)当用户点击“Button 4”的时候会输出什么到控制台,为何?
不管用户点击什么按钮,数字5将总会输出到控制台。这是由于,当 onclick 方法被调用(对于任何按钮)的时候, for 循环已经结束,变量 i 已经得到了5的值。
(b)提供一个或多个备用的可按预期工做的实现方案?
要让代码工做的关键是,经过传递到一个新建立的函数对象,在每次传递经过 for 循环时,捕捉到 i 值。下面是三种可能实现的方法:
方法一
for (var i = 0; i < 5; i++) {
var btn = document.createElement('button'); btn.appendChild(document.createTextNode('Button ' + i)); btn.addEventListener('click', (function(i) { return function() { console.log(i); }; })(i)); document.body.appendChild(btn);
}
方法二: 封装所有调用到在新匿名函数中的 btn.addEventListener
for (var i = 0; i < 5; i++) {
var btn = document.createElement('button'); btn.appendChild(document.createTextNode('Button ' + i)); (function (i) { btn.addEventListener('click', function() { console.log(i); }); })(i); document.body.appendChild(btn);
}
方法三: 调用数组对象的本地 forEach 方法来替代 for 循环
['a', 'b', 'c', 'd', 'e'].forEach(function (value, i) {
var btn = document.createElement('button'); btn.appendChild(document.createTextNode('Button ' + i)); btn.addEventListener('click', function() { console.log(i); }); document.body.appendChild(btn);
});
var arr1 = "john".split(''); var arr2 = arr1.reverse(); var arr3 = "jones".split(''); arr2.push(arr3); console.log("array 1: length=" + arr1.length + " last=" + arr1.slice(-1)); console.log("array 2: length=" + arr2.length + " last=" + arr2.slice(-1));
输出结果是:
"array 1: length=5 last=j,o,n,e,s""array 2: length=5 last=j,o,n,e,s"
调用数组对象的 reverse() 方法并不仅返回反顺序的阵列,它也反转了数组自己的顺序(即,在这种状况下,指的是 arr1)。
reverse() 方法返回一个到数组自己的引用(在这种状况下即,arr1)。其结果为,arr2 仅仅是一个到 arr1的引用(而不是副本)。所以,当对 arr2作了任何事情(即当咱们调用 arr2.push(arr3);)时,arr1 也会受到影响,由于 arr1 和 arr2 引用的是同一个对象。
注意:
传递数组到另外一个数组的 push() 方法会让整个数组做为单个元素映射到数组的末端。其结果是,语句 arr2.push(arr3); 在其总体中添加 arr3 做为一个单一的元素到 arr2 的末端(也就是说,它并无链接两个数组,链接数组是 concat() 方法的目的)。
和Python同样,JavaScript标榜数组方法调用中的负数下标,例如 slice() 可做为引用数组末尾元素的方法:例如,-1下标表示数组中的最后一个元素,等等。
console.log(1 + "2" + "2"); console.log(1 + +"2" + "2"); console.log(1 + -"1" + "2"); console.log(+"1" + "1" + "2"); console.log( "A" - "B" + "2"); console.log( "A" - "B" + 2);
上面的代码将输出如下内容到控制台:
"122""32""02""112""NaN2"NaN
根本缘由是,JavaScript(ECMAScript)是一种弱类型语言,它可对值进行自动类型转换,以适应正在执行的操做。让咱们经过上面的例子来讲明这是如何作到的。
例1:1 + "2" + "2" 输出:"122" 说明: 1 + "2" 是执行的第一个操做。因为其中一个运算对象("2")是字符串,JavaScript会假设它须要执行字符串链接,所以,会将 1 的类型转换为 "1", 1 + "2"结果就是 "12"。而后, "12" + "2" 就是 "122"。
例2: 1 + +"2" + "2" 输出: "32" 说明:根据运算的顺序,要执行的第一个运算是 +"2"(第一个 "2" 前面的额外 + 被视为一元运算符)。所以,JavaScript将 "2" 的类型转换为数字,而后应用一元 + 号(即,将其视为一个正数)。其结果是,接下来的运算就是 1 + 2 ,这固然是 3。而后咱们须要在一个数字和一个字符串之间进行运算(即, 3 和 "2"),一样的,JavaScript会将数值类型转换为字符串,并执行字符串的链接,产生 "32"。
例3: 1 + -"1" + "2" 输出: "02" 说明:这里的解释和前一个例子相同,除了此处的一元运算符是 - 而不是 +。先是 "1" 变为 1,而后当应用 - 时又变为了 -1 ,而后将其与 1相加,结果为 0,再将其转换为字符串,链接最后的 "2" 运算对象,获得 "02"。
例4: +"1" + "1" + "2" 输出: "112" 说明:虽然第一个运算对象 "1"由于前缀的一元 + 运算符类型转换为数值,但又当即转换回字符串,当链接到第二个运算对象 "1" 的时候,而后又和最后的运算对象"2" 链接,产生了字符串 "112"。
例5: "A" - "B" + "2" 输出: "NaN2" 说明:因为运算符 - 不能被应用于字符串,而且 "A" 和 "B" 都不能转换成数值,所以,"A" - "B"的结果是 NaN,而后再和字符串 "2" 链接,获得 "NaN2" 。
例6: "A" - "B" + 2 输出: NaN 说明:参见前一个例子, "A" - "B" 结果为 NaN。可是,应用任何运算符到NaN与其余任何的数字运算对象,结果仍然是 NaN。
var list = readHugeList(); var nextListItem = function() { var item = list.pop(); if (item) { // process the list item... nextListItem(); } };
潜在的堆栈溢出能够经过修改nextListItem 函数避免:
var list = readHugeList(); var nextListItem = function() { var item = list.pop(); if (item) { // process the list item... setTimeout( nextListItem, 0); } };
堆栈溢出之因此会被消除,是由于事件循环操纵了递归,而不是调用堆栈。当 nextListItem 运行时,若是 item不为空,timeout函数(nextListItem)就会被推到事件队列,该函数退出,所以就清空调用堆栈。当事件队列运行其timeout事件,且进行到下一个 item 时,定时器被设置为再次调用 extListItem。所以,该方法从头至尾都没有直接的递归调用,因此不管迭代次数的多少,调用堆栈保持清空的状态。
for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, i * 1000 ); }
解释你的答案。闭包在这里能起什么做用?
上面的代码不会按预期显示值0,1,2,3,和4,而是会显示5,5,5,5,和5。
缘由是在循环中执行的每一个函数将整个循环完成以后被执行,所以,将会引用存储在 i中的最后一个值,那就是5。
闭包能够经过为每次迭代建立一个惟一的范围,存储范围内变量的每一个惟一的值,来防止这个问题,以下:
for (var i = 0; i < 5; i++) { (function(x) { setTimeout(function() { console.log(x); }, x * 1000 ); })(i); }
这就会按预期输出0,1,2,3,和4到控制台。
console.log("0 || 1 = "+(0 || 1)); console.log("1 || 2 = "+(1 || 2)); console.log("0 && 1 = "+(0 && 1)); console.log("1 && 2 = "+(1 && 2));
该代码将输出:
0 || 1 = 11 || 2 = 10 && 1 = 01 && 2 = 2
在JavaScript中, || 和 &&都是逻辑运算符,用于在从左至右计算时,返回第一个可彻底肯定的“逻辑值”。
或( || )运算符。在形如 X||Y的表达式中,首先计算X 并将其解释执行为一个布尔值。若是这个布尔值true,那么返回true(1),再也不计算 Y,由于“或”的条件已经知足。若是这个布尔值为false,那么咱们仍然不能知道 X||Y是真是假,直到咱们计算 Y,而且也把它解释执行为一个布尔值。
所以, 0 || 1 的计算结果为true(1),同理计算1 || 2。
与( &&)运算符。在形如 X&&Y的表达式中,首先计算 X并将其解释执行为一个布尔值。若是这个布尔值为 false,那么返回 false(0),再也不计算 Y,由于“与”的条件已经失败。若是这个布尔值为true,可是,咱们仍然不知道 X&&Y 是真是假,直到咱们去计算 Y,而且也把它解释执行为一个布尔值。
不过,关于 &&运算符有趣的地方在于,当一个表达式计算为“true”的时候,那么就返回表达式自己。这很好,虽然它在逻辑表达式方面计算为“真”,但若是你但愿的话也可用于返回该值。这就解释了为何,有些使人奇怪的是, 1 && 2返回 2(而不是你觉得的可能返回 true 或 1)。
console.log(false == '0') console.log(false === '0')
代码将输出:
true false
在JavaScript中,有两种等式运算符。三个等于运算符 === 的做用相似传统的等于运算符:若是两侧的表达式有着相同的类型和相同的值,那么计算结果为true。而双等于运算符,会只强制比较它们的值。所以,整体上而言,使用 ===而不是 ==的作法更好。 !==vs !=亦是同理。
var a={}, b={key:'b'}, c={key:'c'}; a[b]=123; a[c]=456; console.log(a[b]);
这段代码将输出 456(而不是 123)
缘由为:当设置对象属性时,JavaScript会暗中字符串化参数值。在这种状况下,因为 b 和 c都是对象,所以它们都将被转换为"[object Object]"。结果就是, a[b]和a[c]均至关于a["[object Object]"] ,并能够互换使用。所以,设置或引用 a[c]和设置或引用 a[b]彻底相同。
console.log((function f(n){return ((n > 1) ? n * f(n-1) : n)})(10));
代码将输出10!的值(即10!或3628800)。
缘由是:
命名函数 f()递归地调用自己,当调用 f(1)的时候,只简单地返回1。下面就是它的调用过程:
f(1): returns n, which is 1f(2): returns 2 f(1), which is 2f(3): returns 3 f(2), which is 6f(4): returns 4 f(3), which is 24f(5): returns 5 f(4), which is 120f(6): returns 6 f(5), which is 720f(7): returns 7 f(6), which is 5040f(8): returns 8 f(7), which is 40320f(9): returns 9 f(8), which is 362880f(10): returns 10 * f(9), which is 3628800
(function(x) { return (function(y) { console.log(x); })(2) })(1);
控制台将输出 1,即便历来没有在函数内部设置过x的值。缘由是:
闭包是一个函数,连同在闭包建立的时候,其范围内的全部变量或函数一块儿。在JavaScript中,闭包是做为一个“内部函数”实施的:即,另外一个函数主体内定义的函数。闭包的一个重要特征是,内部函数仍然有权访问外部函数的变量。
所以,在本例中,因为 x未在函数内部中定义,所以在外部函数范围中搜索定义的变量 x,且被发现具备1的值。
var hero = { _name: 'John Doe', getSecretIdentity: function (){ return this._name; } }; var stoleSecretIdentity = hero.getSecretIdentity; console.log(stoleSecretIdentity()); console.log(hero.getSecretIdentity());
代码将输出:
undefinedJohn Doe
第一个 console.log之因此输出 undefined,是由于咱们正在从 hero对象提取方法,因此调用了全局上下文中(即窗口对象)的 stoleSecretIdentity(),而在此全局上下文中, _name属性不存在。
其中一种修复stoleSecretIdentity() 函数的方法以下:
var stoleSecretIdentity = hero.getSecretIdentity.bind(hero);
此函数的参数为:
DOM元素
回调函数(将DOM元素做为其参数)
访问树(DOM)的全部元素是经典的深度优先搜索算法应用。下面是一个示范的解决方案:
function Traverse(p_element,p_callback) { p_callback(p_element); var list = p_element.children; for (var i = 0; i < list.length; i++) { Traverse(list[i],p_callback); // recursive call } }
这道题的代码具体不清了,考查的是数组相似下面这样
var a = [,1], b = [,1,,1], c = [1,]; console.log(a.length); console.log(b.length); console.log(c.length);
打印: 2 4 1
A eval
B parseFloat
C setTimeout
D alert
E enscape
答案: ABCDE
A var a = () B var b = {} C var c = [] D var d =
答案: A
A JSONP
B script 标签
C iframe 和 location.hash
D flash
E postMessage
答案: ABCDE
参考:http://www.cnblogs.com/rainma...
var foo = 1; function(){ console.log(foo); var foo = 2; console.log(foo); }
输出undefined 和 2
console.log(1 && 2);
输出: 2
console.log(1+"2"+"2"); console.log(1+ +"2"+"2"); console.log(1+ -"1"+2); console.log(1+ -"1"+"2"); console.log(+"1"+2); console.log(1+ "2"); console.log("A"-"B"+"2"); console.log("A"-"B"+2);
输出: 122 32 2 02 3 12 NaN2 NaN