js基础知识

疑问一:变量声明提升

代码片段一

1
2
3
4
var a = "hello";
(function(){
console.log(a); /输出hello
})();

代码片段二

1
2
3
4
5
var a = "hello";
(function(){
console.log(a); /输出undefined
var a = "nima";
})();

在IIF函数(立即执行函数)的执行上下文中,由于变量声明的提升,沿着作用域链开始逐级向上回溯搜素时,在IIF函数内找到了a变量,上述代码相当于:

1
2
3
4
5
6
var a = "hello";
(function(){
var a;
console.log(a);
a = "nima";
})();

参考资料:

612-235-4722疑问二:函数声明和函数表达式

代码片段一

1
2
3
4
5
6
7
8
9
10
11
12
/ foo(); / 2
/ 函数表达式
var foo = function() {
console.log("1");
};

/ foo(); / 1
/ 函数声明
function foo() {
console.log("2");
}
/ foo(); / 1

由于函数声明提升总是优先于变量声明提升,因此即使将上述函数表达式和函数声明对调,输出的结果仍不变。上述代码相当于:

1
2
3
4
5
6
7
8
9
10
11
12
function foo() {
console.log("2");
}
var foo;
/ foo(); / 2

foo = function() { / 覆盖了函数声明
console.log("1");
};

/ foo(); / 1
/ foo(); / 1

注意:在代码开始执行之前,解析器就已经通过一个名为函数声明提升(function declaration hoisting)的过程,读取并将函数声明添加到执行环境中。而对于函数表达式,代码只会在函数所在语句之后,才能执行。

(203) 500-7331疑问三:带标识符的函数表达式

在segmentfault看到的一个问题,从这个问题又了解到了“词法记录器”:
代码片段一:

1
2
3
4
5
6
7
8
b = c;
b();
console.log(a); /1
console.log(b); /2
console.log(c); /3
function c() {
a = 1; b = 2; c = 3;
}

解读:这段代码关乎声明提升(Hoisting),c函数内部的变量没有使用var声明,所以本来b和c为function c() {},被分别覆盖为2和3了。

在代码片段一的基础上修改为以下:
代码片段二:

1
2
3
4
5
6
7
b = function c() {
a = 1; b = 2; c = 3;
};
b();
console.log(a); /1
console.log(b); /2
console.log(c); /Uncaught ReferenceError: c is not defined

众所周知,JS的变量和函数声明都会被存储到执行上下文的变量对象(或活动对象)中,即声明提前。

解读:
在JS中函数有两种定义方式:

1. 函数声明:

    其中函数声明只有一种形式: 
    function 标识符(形参) {函数代码} 

2. 函数表达式

    而函数表达式有两种形式:
    function 标识符(形参) {函数代码} 
    function (形参) {函数代码} 

对于函数表达式的第一种写法,var bar = function foo() {};这个标识符标量只在函数的作用域内有效,并且不会被覆盖,在函数外围无效(在IE8及IE8以下浏览器却是可见的)。所以代码片段三,C输出为function c() {};而不是3

在代码片段二的基础上修改为以下:
代码片段三:

1
2
3
4
5
6
7
b = function c() {
a = 1; b = 2; c = 3;
console.log(a); /1
console.log(b); /2
console.log(c); /function c() {...}
};
b();

相关资料:

疑问四:js高级程序(闭包与变量)代码

闭包是指:当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数内部的其它变量,如果返回的这个函数在外部被执行,就产生了闭包。——摘自弄懂JavaScript的作用域和闭包

javascript高级程序设计(第三版) 7.2.1闭包与变量

1
2
3
4
5
6
7
8
9
10
11
12
function createFunctions() {
var result = new Array();
for(var i = 0; i < 10; i++) {
result[i] = function(num){
/return function() {
return num;
/};
}(i);
}
return result;
}
createFunctions();

原书上的代码似乎要改成这样,result数组里才会存放每一个i的值。如若像书本那样写,result的值将会是:
"书本代码得到的result数组"
经过修改后的代码的result的值:
"修改后的代码的result数组"

(425) 670-4958拓展:

疑问五:事件委托机制

随着内存中的对象越多,性能越差,而且,添加到页面上的事件处理程序数量会直接关系到页面的整体性能。随后,便出现了事件委托机制。使用事件委托技术能让你避免对特定的每个节点添加事件监听器;相反,事件监听器是被添加到它们的父元素上。事件监听器会分析从子元素冒泡上来的事件,找到是哪个子元素的事件。

代码示例:

1
2
3
4
5
<ul id="list">
<li>列表1</li>
<li>列表2</li>
<li>列表3</li>
</ul>
1
2
3
4
var list = document.getElementById("list");
list.addEventListener("click",function(){
console.log(event.target.innerHTML);
},false);

疑问六:call函数

Chrome36控制台下执行下列代码,为何输出this的时候,不是基本类型值String?

1
2
3
4
5
6
var a = function(){
console.log(this);/ String {0: "l", 1: "i", 2: "t", 3: "t", 4: "l", 5: "e", 6: "d", 7: "u", length: 8}
console.log(typeof this); / object
console.log(this instanceof String); / true
}
a.call('littledu');

7057702720疑问七:Array.prototype.slice.call/apply()

更多时候,该方法一般运用到array-like类数组上,因为这种数据没有数组所特有的属性和方法。类似:函数内部的arguments对象,它类似于数组,没有数组所特有的属性和方法,除了length。

注意:在MDN中,对arguments运用Array.prototype.slice提出了警告……不应在 arguments 对象上使用 slice 方法,这会阻碍 JavaScript 引擎的优化 (比如 V8 引擎)。作为替代,应通过遍历arguments对象的方式来构建一个新的数组。

7022222559相关资料:

疑问八:setTimeout(fn, 0)

2317693644基本概念

在HTML5规范之前,setTimeout和setInterval方法接受两个参数:要执行的代码和以毫秒表示的时间。以前,为了给要执行的代码传递参数,需要利用闭包来实现,比如:

1
2
3
4
5
6
7
8
9
10
11
12
/ 一秒后在控制台输出1
var timer = setTimeout(function() {
console.log(1);
}, 1000);

/ 现要求1秒后,在控制台输出a的值
var a = 1;
var timer = setTimeout(function(a) {
return function() {
console.log(a);
};
}(a), 1000);

在HTML5规范出来之后,setTimeout和setInterval除了第一、二个参数外,还可以接受其它参数传入要执行的代码中,例如:

1
2
3
4
var a = 1;
var timer = setTimeout(function() {
console.log(arguments[0]);
}, 1000, a);

9253223310setTimeout(fn, 0)

在segementfault平台头条里面看到了一篇比较有趣的文章:902-240-8655。观察分析里面的每一个小示例:

相关资料:

(209) 427-0681

笔记搬迁自之前的笔记集


第二个函数只因为return后的大括号换行了,导致它与预期返回的结果不一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function foo1(){
return {
bar: "hello"
};
}

function foo2(){
return
{
bar: "hello"
};
}
console.log("foo1 returns:");
console.log(foo1());
console.log("foo2 returns:");
console.log(foo2());
1
2
3
4
5
/ 最终结果
foo1 returns:
Object {bar: "hello"}
foo2 returns:
undefined

原因是:
浏览器在解析下述代码片段一时,会解析成类似代码片段二的形式,故函数返回的结果为undefined。

1
2
3
4
5
6
7
/ 代码片段一
return
{
bar: "hello"
};
/ 代码片段二
return;{bar:"hello"};

9068321964相关资料

(530) 509-4753

背景

对于我而言,闭源项目都在determination上托管,而开源项目都托管在github上。二者都是基于Git的开源分布式版本控制系统,在本地可以通过SSH协议进行远程登录验证和数据传输,而使用该协议需要在托管平台上配置公钥,客户端(电脑)存放公钥对应的密钥。

默认情况下,在同一客户端(电脑)生成密钥时,密钥所存放的文件位置和文件名称是相同的(默认为C:\Users\spin.ssh\id_rsa和C:\Users\spin.ssh\id_rsa.pub),那么就会出现新生成的密钥覆盖原来的密钥。所以,我们需要将区分开不同代码托管平台的密钥文件。

705-685-2715生成公私密钥

一、闭源项目托管在coding上,那么:

  1. 任意打开一个目录,打开git命令行;

  2. 执行ssh-keygen -t rsa -C “{你的邮箱}”;

  3. 接下来会询问你存放密钥的路径和文件名称Enter file in which to save the key (/c/Users/{用户名}/.ssh/id_rsa),假设存储为/c/Users/{用户名}/.ssh/codingnet_rsa,如果不填默认文件名就是id_rsa;

  4. 接下来还会询问你是否需要登录密码,可以设置也可以不设置;

  5. 最终,打开C:\Users{用户名}.ssh目录,将发现目录下生成了codingnet_rsa和codingnet_rsa.pub两个文件。

    生成公私有密钥步骤:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    winsycwen@DESKTOP-GRBPS3N MINGW64 ~
    $ ssh-keygen -t rsa -C "{你的邮箱}"
    Generating public/private rsa key pair.
    Enter file in which to save the key (/c/Users/{用户名}/.ssh/id_rsa): /c/Users/{用户名}/.ssh/codingnet_rsa
    Created directory '/c/Users/{用户名}/.ssh'.
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in /c/Users/{用户名}/.ssh/codingnet_rsa.
    Your public key has been saved in /c/Users/{用户名}/.ssh/codingnet_rsa.pub.
    The key fingerprint is:
    SHA256:xxxxxxxxxxxxxxxxx {你的邮箱}
    The key's randomart image is:xxxxxxxxxxxxxxxxxxxxxxxxxx

二、开源项目托管在github上,那么:

  1. 步骤同上,只是在第2步将密钥文件命名为github_rsa。

  2. 最终,打开C:\Users{用户名}.ssh目录,将发现目录下生成了github_rsa和github_rsa.pub两个文件。

分别配置公用密钥

一、对于闭源项目:

  1. 打开C:\Users{用户名}.ssh\codingnet_rsa.pub并复制里面的内容;

  2. 打开coding并登录,找到配置SSH公钥的页面并添加SSH公钥;

二、对于开源项目:

  1. 打开C:\Users{用户名}.ssh\github_rsa.pub并复制里面的内容;

  2. 打开(815) 297-3835并登录,找到配置SSH公钥的页面并添加SSH公钥;

(765) 768-7766检测有效性

由于,首次建立连接需要获得主机的信任,因此需要执行下列操作:

一、对于闭源项目:

  1. 打开git命令行,执行ssh-agent bash,然后执行ssh-add ~/.ssh/codingnet_rsa;

    1
    2
    3
    winsycwen@DESKTOP-GRBPS3N MINGW64 /d/study/project
    $ ssh-add ~/.ssh/codingnet_rsa
    Identity added: /c/Users/winsycwen/.ssh/codingnet_rsa (/c/Users/winsycwen/.ssh/codingnet_rsa)
  2. 执行ssh -T git@git.coding.net

    1
    2
    3
    4
    winsycwen@DESKTOP-GRBPS3N MINGW64 /d/study/project
    $ ssh -T git@git.coding.net
    Coding 提示: Hello winsycwen, You've connected to Coding.net via SSH. This is a personal key.
    winsycwen,你好,你已经通过 SSH 协议认证 Coding.net 服务,这是一个个人公钥
  3. 最后,我们可以测试一下,例如执行git clone 757-308-2078:{用户名}/{仓库名}.git

二、对于开源项目:

  1. 打开git命令行,执行ssh-agent bash,然后执行ssh-add ~/.ssh/github_rsa;

    1
    2
    3
    winsycwen@DESKTOP-GRBPS3N MINGW64 /d/study/project
    $ ssh-add ~/.ssh/github_rsa
    Identity added: /c/Users/winsycwen/.ssh/github_rsa (/c/Users/winsycwen/.ssh/github_rsa)
  2. 执行ssh -T woe-bested

    1
    2
    3
    winsycwen@DESKTOP-GRBPS3N MINGW64 /d/study/project
    $ ssh -T git@github.com
    Hi winsycwen! You've successfully authenticated, but GitHub does not provide shell access.
  3. 最后,我们可以测试一下,例如执行git clone git@github.com:{用户名}/{仓库名}.git