做者:valentinogagliardihtml
译者:前端小智前端
来源:githubgit
阿里云最近在作活动,低至2折,有兴趣能够看看:github
promotion.aliyun.com/ntms/yunpar…web
为了保证的可读性,本文采用意译而非直译。编程
JS 是一种用于 web 的脚本语言。JS 诞生于 1995
年,由 **Brendan Eich **一手建立,用于向web页面添加交互性。那时的互联网还处于起步阶段,咱们今天看到的大多数花哨的网页在那时候还只是一个梦。数组
在项目经理的催促下,Brendan 只有 10
天的时间来建立一种能够在浏览器中运行的动态、灵活的语言。他写出了 JavaScript,一种有点奇怪的编程语言,它参考了 Java、C 和 Scheme。JS 一直名声很差,由于它从一开始就有不少怪异的地方。但尽管如此,它仍是在名人堂占据了一席之地,并一直挺到了今天。浏览器
如今,JS 被用来建立整个应用程序,称为SPA(单页应用程序)。随着使用量的增长,JS 生态系统也经历了寒武纪大爆发。我们今天用于开发 JS 的大多数 Web 工具和库,不少用 JS 写的。JS 也被用除前端方面的领域。使用 Node.js
我们能够建立服务器端和物联网应用程序,工业设备,以及更多。但最重要的是,单页应用程序是 JS 最突出的用法之一。bash
在单页面应用中,JS 负责全部的事情,使 UI 流畅,无需任何页面刷新。从用户的角度来看,这是对传统 web 应用程序的巨大改进。可是,能力越大,责任越大: JS 对于大多数移动设备来讲是一个沉重的负担,在设计和构建时应该格外当心。、服务器
今天学习 JS 并不意味着对变量和函数的肤浅理解:还有不少。JS 开发人员知道闭包、this
、new
、原型系统和更新的特性。JS 一年比一年流行,功能也逐渐完善。如今几乎每一个前端开发人员的工做都须要 JS 知识。招聘经理寻找的不是会使用 JQ (说到jQuery,它彷佛正在慢慢消亡) 的。
大多数状况下,你也须要解及学习 TypeScript, 强调类型的 JS。前端开发人员应该要理解 JS 的特性,并可以编写惯用的、结构良好的 JS 代码。JS 正在迅速传播,即便你不喜欢这种语言,在这一点上忽视它也可能对你的职业生涯不利。
JS 目前有 7 种基本类型,以下:
String
Number
Boolean
Null
Undefined
Object
Symbol
(ES6)除了 Object
是复杂数据类型外,其它的 6 种是 JS 的基本数据类型。每一个 JS 类型都有一个对应的表示,能够在我们的代码中使用,好比字符串:
var string = "Hello John";
复制代码
数字:
var age = 33;
复制代码
说到这里,JS 也有算术运算:
运算符 | 运算名 |
---|---|
+ | 加法 |
++ | 自增 |
* | 乘法 |
** | 指数 |
- | 减 |
-- | 自减 |
/ | 除 |
% | 取除 |
在 JS 中,可使用 var
关键字将值存储在变量中,这是声明变量的最兼容方法:
var greet = "Hello";
var year = 89;
var not = false;
复制代码
这里说的兼容,是由于在 ES6 中咱们还有两个选择: let
和 const
。旧的浏览器可能不支持这些新的关键字,除非使用“转置器”,不然可能会遇到错误。在新的浏览器中,建议都 let
和 const
。主要有两个好处:
let
和 const
都有本身的块做用域const
不能从新分配,也不能从新声明块做用域是指用 let
或 const
声明的变量与在封闭或外部块
中声明的相同变量名不重叠。例如:
let name = "前端小智";
{
let name = "王大冶";
console.log(name); // "王大冶"
}
console.log(name); // "前端小智"
复制代码
这里的 name
彷佛是重复的,但其实是两个不一样的变量在本身的做用域里。const
具备相同的行为:
const name = "前端小智";
{
const name = "王大冶";
console.log(name); // "王大冶"
}
console.log(name); // "前端小智"
复制代码
与 var
的行为就与 let
和 const
不同了。
var name = "前端小智";
{
var name = "王大冶";
console.log(name); // "王大冶"
}
console.log(name); // "王大冶"
复制代码
正如前端所说,const
不能被从新分配,也不能在同一个做用域中从新声明。若是你尝试从新声明一个 const
,会获得 "SyntaxError: Identifier has already been declared"
。若是将某个值从新赋值给同一个 const
,会获得 "TypeError: Assignment to constant variable"
错误。
const name = "前端小智";
const name = "王大冶";
// SyntaxError: Identifier 'name' has already been declared
复制代码
下面代码也会抛出错误:
const name = "前端小智";
name = "王大冶";
// TypeError: Assignment to constant variable.
复制代码
可是,请注意,这里所说的 “cons 不能从新分配,也不能从新声明”
时,并不意味着const 是不可变的。
这是初学者都会遇到的问题。事实上,任何稍微复杂一点的 JS 数据结构,如数组或对象,即便在分配给 const
时,它们的值或者属性值是可变的,不可变是指这些复杂对象的内存地址。
const person = {
name: "前端小智",
age: 21
};
person.name = "王大冶";
console.log(person);
// {name: "王大冶", age: 21}
复制代码
const 对象中的不可变是指什么? 下面是数组:
const list = [1, 1, 3, 2, 5];
list.shift();
console.log(list); // [ 1, 3, 2, 5 ]
复制代码
一样,不是不可变。 有人说 “const 是不可变” 时,请给他看这些例子。 如今回到基础。 除了独立变量以外,还可使用字面量的方式声明数组:
var array = ["Hello", 89, false, true];
复制代码
从 0
开始的索引能够访问数组元素:
var array = ["Hello", 89, false, true];
var first = array[0]; // "Hello"
复制代码
几乎全部 JS 实体都附加了一些函数,称为方法。举两个例子,数组有不少处理自身的方法
var array = ["Hello", 89, false, true];
array.push(99);
array.shift();
console.log(array); // [ 89, false, true, 99 ];
复制代码
对于字符串也是同样的:
var string = "John";
console.log(string.toUpperCase()); // JOHN
复制代码
在第 5 章中,你会知道这些方法从何而来,但这里有一个提示:它们分别在 Array.prototype
和 String.prototype
上定义。除了方法以外,还有一些属性对于提取关于字符串长度的信息很是有用:
var string = "John";
console.log(string.length); // 4
复制代码
或者数组的长度:
var array = ["Hello", 89, false, true];
array.push(99);
array.shift();
console.log(array.length); // 4
复制代码
这些属性有些特殊,由于它们被称为 "getters"/"setters"
。 你能够想象一个给定的字符串就像一个附加了一堆方法和属性的对象。当访问数组的长度时,你只需调用相应的 getter
。setter
函数用于设置操做:
var array = {
value: ["Hello", 89, false, true],
push: function(element) {
//
},
shift: function() {
//
},
get length() {
// gets the length
},
set length(newLen) {
// sets the length
}
};
// Getter call
var len = array.length
// Setter call
array.length = 50;
复制代码
如今,我们已经奠基了基础,让咱们仔细看看对象,它是最重要的 JS 类型之一。
Object
是 JS 中最重要的类型,所以几乎全部其余实体均可以从中派生。 例如,函数和数组是专用对象。 JS 中的对象是键/值对的容器,如如下示例(字面量形式):
var obj = {
name: "John",
age: 33
};
复制代码
还有另外一种建立对象的方法,但它不多见,性能低,请避免使用这种形式:
var obj = new Object({
name: "John",
age: 33
});
复制代码
正如你所看到的,对象是保存值的一种方便方法,稍后能够经过访问相应的属性来检索这些值:
var obj = {
name: "前端小智",
age: 26
};
console.log(obj.name); // "前端小智"
复制代码
我们还能够添加新属性、删除或更改它们
var obj = {
name: "前端小智",
age: 26
};
obj.address = "王大冶";
delete obj.name;
obj.age = 18;
复制代码
对象的键也能够是字符串,在本例中,咱们使用方括号符号访问属性:
var obj = {
name: "前端小智",
age: 26,
"complex key": "stuff"
};
console.log(obj["complex key"]); // "stuff"
复制代码
可是,点表示法更常见,除非键是复杂的字符串,不然应该选择传统的属性访问:
var obj = {
name: "前端小智",
age: 26
};
console.log(obj.name); // "前端小智"
复制代码
这是我们全部须要知道的基本知识,但在 第5章,咱们将看到 JS 对象是很是强大的,能够作更多。如今来看看 JS 函数。
几乎每种编程语言都有函数,JS 也不例外。函数是可重用的代码段。考虑如下示例
function hello(message) {
console.log(message);
}
hello("Hello");
复制代码
和
function sum(a, b) {
return a + b;
}
var sum = sum(2, 6);
复制代码
第一个函数打印一个字符串,第二个函数向外部世界返回一个值。正如你所看到的,函数能够接受参数,列在函数“签名”中:
// a 和 b 是函数签名中的参数
function sum(a, b) {
return a + b;
}
复制代码
我们能够在调用函数时传递值:
// a and b are parameters in the function's signature
function sum(a, b) {
return a + b;
}
// 2 和 6 是该函数的参数
var sum = sum(2, 6);
复制代码
用 function
关键字声明的 JS 函数是常规函数,与没有主体的肩头函数相反常规函数能够呈现多种形式:
命名函数是最传统的函数类型:
function sum(a, b) {
return a + b;
}
复制代码
另外一方面,匿名函数没有名称,能够分配给一个变量供之后使用
var sum = function(a, b) {
return a + b;
};
复制代码
或者用做其余函数中的回调:
var button = document.createElement("button");
button.addEventListener("click", function(event) {
// do stuff
});
复制代码
函数也能够存在于对象中,这种称为该对象的方法:
var widget = {
showModal: function() {
// do stuff
}
};
widget.showModal();
复制代码
常规函数在默认状况下也会获得一个 this
关键字,它能够根据调用函数的方式赋予不一样的含义。在第六章中,咱们将详细探讨这个主题。如今有一个简单的规则:在一个对象内部运行的函数有 this
指向包含对象的指针
var widget = {
html: "<div></div>",
showModal: function() {
console.log(this.html);
}
};
widget.showModal(); // "<div></div>"
复制代码
在 ES6 中,你也可使用对象方法简写:
var widget = {
showModal() {
// object method shortand
}
};
widget.showModal();
复制代码
最后,IIFE
(当即执行的函数):
var IIFE = (function() {
// what happens in an IIFE stays in the IIFE
})();
复制代码
语法可能看起来有点奇怪,可是 IIFE 很是强大,在第4章会看到它们。除了常规函数外,还有箭头函数,在 ES6 中添加。箭头函数不使用 function
关键字,但它们具备类似的形式:
箭头函数很方便,但我建议不要过分使用它们。这是一个命名的箭头函数。若是没有参数,能够省略 return
语句并使用圆括号:
const arrow = () => console.log("Silly me");
复制代码
若是你须要在箭头函数中计算一些东西或者调用其余函数,能够用花括号包含一个主体
const arrow = () => {
const a = callMe();
const b = callYou();
return a + b;
};
复制代码
花括号也是定义对象的字面量形式,这并不意味着我们能够作相似的事情:
const arrow = () => {
a : "hello",
b: "world"
};
复制代码
这是无效的语法。要从箭头函数返回对象,可使用圆括号:
const arrow = () => ({
a: "hello",
b: "world"
});
console.log(arrow());
// { a: 'hello', b: 'world' }
复制代码
或者使用 return
语句:
const arrow = () => {
return {
a: "hello",
b: "world"
};
};
复制代码
与常规匿名函数同样,也有匿名箭头函数。这里有一个做为回调传递给另外一个函数
const arr = [1, 2, 3];
const res = arr.map(element => element + 1);
console.log(res); // [ 2, 3, 4 ]
复制代码
它以 element
为参数,并为每一个数组元素返回 element +1
。 如你所见,若是箭头函数只有一个参数,则无需在其周围加上括号:
const fun = singleParameter => singleParameter + 1;
复制代码
但若是你须要更多的参数,括号是必需的:
const fun = (a, b) => a + b + 1;
复制代码
箭头函数也能够做为对象方法出现,可是它们的行为与常规函数不一样。在前一段介绍了 this
关键字,它是对运行函数的对象的引用。看成为对象方法调用时,常规函数将 this
指向宿主对象
var widget = {
html: "<div></div>",
showModal: function() {
console.log(this.html);
}
};
widget.showModal(); // "<div></div>"
复制代码
而箭头函数中的 this
则指向彻底不一样的东西:
var widget = {
html: "<div></div>",
showModal: () => console.log(this.html)
};
widget.showModal(); // undefined
复制代码
所以,箭头函数不太适合做为对象方法,可是有一些有趣的用例,在本小册中,我们将了解为何以及什么时候有效使用它们。 最后,来看一下 IIFE 箭头函数:
(() => {
console.log("aa");
})();
复制代码
使人困惑的语法不是吗? 接着我们将进入下一章。
**ECMAScript 中全部函数的参数都是按值传递的。**也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另外一个变量同样。基本类型值的传递如同基本类型变量的复制同样,而引用类型值的传递,则如同引用类型变量的复制同样。有很多开发者在这一点上可能会感到困惑,由于访问变量有按值和按引用两种方式,而参数只能按值传递。
在向参数传递基本类型时,被传递的值会被复制给一个局部变量(即命名参数,或者用 ECMAScript 的概念来讲,就是 arguments
对象中的一个元素)。在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,所以这个局部变量的变化会反映在函数的外部。请看下面的例子:
function addTen(num){
num += 10;
return num
}
var count = 20;
var result = addTen(count);
alert(count); // 20 没有变化
alert(result); // 30
复制代码
这里的函数 addTen ()
有一个参数 num ,而参数其实是函数的局部变量。在调用这个函数时,变量 count
做为参数被传递给函数,这个变量的值是 20
。因而,数值 20
被复制给参数 num
以便在 addTen()
中使用。 在函数内部,参数 num
的值被加上了 10
,但这一变化不会影响函数外部的 count
变量。参数的值也将变成 30
,从而反映函数内部的修改。固然,使用数值等基本类型值来讲明按值传递参数比较简单,但若是使用对象,那问题就不怎么好理解了。再举一个例子:
function setName (obj) {
obj.name = '前端小智';
}
var person = new Object();
setName(person);
alert(person.name) // "前端小智"
复制代码
以上代码建立一个对象,并将其保存在了变量 person 中。而后,这个变量被传递到 setName() 函数中以后就被复制给了 obj。在这个函数内部, obj 和 person引用的是同一个对象。因而,当在函数内部为 obj 添加 name 属性后,函数外部的 person 也将有所反映;由于person指向的对象在堆内存中只有一个,并且是全局对象。
有不少开发者错误的认为:在局部做用域中修改的对象会在全局做用域中反映出来,就说明参数是按引用传递。为了证实对象是按值传递的,咱们再看一看下面这个通过修改的例子:
function setName(obj) {
obj.name = '前端小智';
obj = new Object();
obj.name = '王大冶'
}
var person = new Object();
setName(person);
alert(person.name) // '前端小智'
复制代码
这个例子与前一个例子的惟一区别,就是在 setName()
函数中添加了两行代码:一行代码为 obj
从新定义了一个对象,另外一行代码为该对象定义了一个带有不一样值的 name
属性。在把 person
传递给 setName()
后,其 name
属性被设置为 ‘前端小智’
。而后,又将一个新对象赋给变量 obj
,同时将其 name
属性设置为 '王大冶'
。
若是 person
是按引用传递的,那么 person
就会自动被修改成指向其 name
属性为 ‘王大冶'
的新对象。可是原始的引用仍然保持不变。实际上,当在函数内部重写 obj
时,这个变量引用就是一个局部对象了。而这个局部对象会在函数执行完毕后当即被销毁。
JS 具备七个称为 “类型” 的基本构建块,其中 6 个也称为基本数据类型。 Object
自己就是一种类型,也是该语言最重要的实体。 对象是用于一对键/值的容器,而且能够包含几乎全部其余 JS 的类型,包括函数。
与大多数其余编程语言同样,JS 有字符串、数字、函数、布尔值和一些称为 Null
和Undefined
的特殊类型。JS 中有两种函数:箭头函数和常规函数。它们都有各自的用法,根据场景使用它们。
arguments 和 参数 之间有什么区别?
JS 中有多少个基本类型
什么是常规的箭头函数
函数做为对象方法运行时能够访问哪些特殊关键字?
在 JS 中声明变量有多少种方法
代码部署后可能存在的BUG无法实时知道,过后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给你们推荐一个好用的BUG监控工具Fundebug。
原文:
阿里云最近在作活动,低至2折,有兴趣能够看看:promotion.aliyun.com/ntms/yunpar…
干货系列文章汇总以下,以为不错点个Star,欢迎 加群 互相学习。
由于篇幅的限制,今天的分享只到这里。若是你们想了解更多的内容的话,能够去扫一扫每篇文章最下面的二维码,而后关注我们的微信公众号,了解更多的资讯和有价值的内容。
每次整理文章,通常都到2点才睡觉,一周4次左右,挺苦的,还望支持,给点鼓励