ECMAScript 6 入门

Pre: 学习JavaScript

摘要:

  • 合并两个数组 - concat()
    如何使用 concat() 方法来合并两个数组。
<html>
<body>
<script type="text/javascript">
var arr = new Array(3)
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
var arr2 = new Array(3)
arr2[0] = "James"
arr2[1] = "Adrew"
arr2[2] = "Martin"
document.write(arr.concat(arr2))
</script>
</body>
</html>
  • 用数组的元素组成字符串 - join()
    如何使用 join() 方法将数组的所有元素组成一个字符串。
<html>
<body>
<script type="text/javascript">
var arr = new Array(3);
arr[0] = "George"
arr[1] = "John"
arr[2] = "Thomas"
document.write(arr.join());
document.write("<br />");
document.write(arr.join("."));
</script>
</body>
</html>

Ref:
ECMAScript 6 入门 - 作者:阮一峰

1.6 Babel 转码器

Babel 是一个广泛使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而在现有环境执行。这意味着,你可以用 ES6 的方式编写程序,又不用担心现有环境是否支持。下面是一个例子。

// 转码前
input.map(item => item + 1);

// 转码后
input.map(function (item) {
  return item + 1;
});

上面的原始代码用了箭头函数,Babel 将其转为普通函数,就能在不支持箭头函数的 JavaScript 环境执行了。

命令行转码babel-cli
Babel 提供babel-cli工具,用于命令行转码。

它的安装命令如下。

$ npm install --global babel-cli

基本用法如下。

# 转码结果输出到标准输出
$ babel example.js

# 转码结果写入一个文件
# --out-file 或 -o 参数指定输出文件
$ babel example.js --out-file compiled.js
# 或者
$ babel example.js -o compiled.js

# 整个目录转码
# --out-dir 或 -d 参数指定输出目录
$ babel src --out-dir lib
# 或者
$ babel src -d lib

# -s 参数生成source map文件
$ babel src -d lib -s

上面代码是在全局环境下,进行 Babel 转码。这意味着,如果项目要运行,全局环境必须有 Babel,也就是说项目产生了对环境的依赖。另一方面,这样做也无法支持不同项目使用不同版本的 Babel。

一个解决办法是将babel-cli安装在项目之中。

# 安装
$ npm install --save-dev babel-cli

然后,改写package.json。

{
  // ...
  "devDependencies": {
    "babel-cli": "^6.0.0"
  },
  "scripts": {
    "build": "babel src -d lib"
  },
}

转码的时候,就执行下面的命令。

$ npm run build
2.1 let 命令

基本用法
ES6 新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

上面代码在代码块之中,分别用let和var声明了两个变量。然后在代码块之外调用这两个变量,结果let声明的变量报错,var声明的变量返回了正确的值。这表明,let声明的变量只在它所在的代码块有效。

在for循环中,let很好用。


May 18

Notes of W3School :

原始值和引用值

在 ECMAScript 中,变量可以存在两种类型的值,即原始值和引用值。
原始值
存储在栈(stack)中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
引用值
存储在堆(heap)中的对象,也就是说,存储在变量处的值是一个指针(point),指向存储对象的内存处。
为变量赋值时,ECMAScript 的解释程序必须判断该值是原始类型,还是引用类型。要实现这一点,解释程序则需尝试判断该值是否为 ECMAScript 的原始类型之一,即 Undefined、Null、Boolean、Number 和 String 型。由于这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域 - 栈中。这样存储便于迅速查寻变量的值。
在许多语言中,字符串都被看作引用类型,而非原始类型,因为字符串的长度是可变的。ECMAScript 打破了这一传统。

如果一个值是引用类型的,那么它的存储空间将从堆中分配。由于引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响。如下图所示:

![原始值和引用值]
(http://www.w3school.com.cn/i/ct_js_value.gif)

typeof 运算符
var sTemp = "test string";
alert (typeof sTemp);    //输出 "string"

对变量或值调用 typeof 运算符将返回下列值之一:

undefined - 如果变量是 Undefined 类型的
boolean - 如果变量是 Boolean 类型的
number - 如果变量是 Number 类型的
string - 如果变量是 String 类型的
object - 如果变量是一种引用类型或 Null 类型的

类型描述
Undefined只有一个值,即undefined
Null只有一个值,即null
Boolean两个值,true和false
Number可以是32位的整数,也可以是64位的浮点数
String它是唯一没有固定大小的原始类型,用""或者’'声明
delete

delete 运算符删除对以前定义的对象属性或方法的引用。例如:

var o = new Object;
o.name = "David";
alert(o.name);	//输出 "David"
delete o.name;
alert(o.name);	//输出 "undefined"
逻辑 NOT 运算符 !
逻辑 AND 运算符:&&
逻辑 OR 运算符:||
条件运算符:

var iMax = (iNum1 > iNum2) ? iNum1 : iNum2;

标签语句

可以用下列语句给语句加标签,以便以后调用:

label : statement
例如:
start : i = 5;
在这个例子中,标签 start 可以被之后的 break 或 continue 语句引用。

with语句

with 语句用于设置代码在特定对象中的作用域。

它的语法:
with (expression) statement
例如:

var sMessage = "hello";
with(sMessage) {
  alert(toUpperCase());	//输出 "HELLO"
}

在这个例子中,with 语句用于字符串,所以在调用 toUpperCase() 方法时,解释程序将检查该方法是否是本地函数。如果不是,它将检查伪对象 sMessage,看它是否为该对象的方法。然后,alert 输出 “HELLO”,因为解释程序找到了字符串 “hello” 的 toUpperCase() 方法。

ECMAScript函数
arguments 对象

在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。

例如,在函数 sayHi() 中,第一个参数是 message。用 arguments[0] 也可以访问这个值,即第一个参数的值(第一个参数位于位置 0,第二个参数位于位置 1,依此类推)。

因此,无需明确命名参数,就可以重写函数:

function sayHi() {
  if (arguments[0] == "bye") {
    return;
  }

  alert(arguments[0]);
}
检测参数个数

还可以用 arguments 对象检测函数的参数个数,引用属性 arguments.length 即可。

下面的代码将输出每次调用函数使用的参数个数:

function howManyArgs() {
  alert(arguments.length);
}

howManyArgs("string", 45);
howManyArgs();
howManyArgs(12);

上面这段代码将依次显示 “2”、“0” 和 “1”。

ECMAScript 的函数实际上是功能完整的对象。
Function 对象(类)

ECMAScript 最令人感兴趣的可能莫过于函数实际上是功能完整的对象。

Function 类可以表示开发者定义的任何函数。

用 Function 类直接创建函数的语法如下:

var function_name = new function(arg1, arg2, ..., argN, function_body)
在上面的形式中,每个 arg 都是一个参数,最后一个参数是函数主体(要执行的代码)。这些参数必须是字符串。

记得下面这个函数吗?

function sayHi(sName, sMessage) {
  alert("Hello " + sName + sMessage);
}

还可以这样定义它:

var sayHi 
= 
new Function("sName", "sMessage", "alert(\"Hello \" + sName + sMessage);");
ECMAScript 最易让人误解的一点是,它支持闭包(closure)。

闭包,指的是词法表示包括不被计算的变量的函数,也就是说,函数可以使用函数之外定义的变量。
简单的闭包实例
在 ECMAScript 中使用全局变量是一个简单的闭包实例。请思考下面这段代码:

var sMessage = "hello world";
function sayHelloWorld() {
  alert(sMessage);
}
sayHelloWorld();

复杂的闭包实例
在一个函数中定义另一个会使闭包变得更加复杂。例如:

var iBaseNum = 10;

function addNum(iNum1, iNum2) {
  function doAdd() {
    return iNum1 + iNum2 + iBaseNum;
  }
  return doAdd();
}

这里,函数 addNum() 包括函数 doAdd() (闭包)。内部函数是一个闭包,因为它将获取外部函数的参数 iNum1 和 iNum2 以及全局变量 iBaseNum 的值。 addNum() 的最后一步调用了 doAdd(),把两个参数和全局变量相加,并返回它们的和。

这里要掌握的重要概念是,doAdd() 函数根本不接受参数,它使用的值是从执行环境中获取的。

关键字 this

this 的功能
在 ECMAScript 中,要掌握的最重要的概念之一是关键字 this 的用法,它用在对象的方法中。关键字 this 总是指向调用该方法的对象,例如:

var oCar = new Object;
oCar.color = "red";
oCar.showColor = function() {
  alert(this.color);
};

oCar.showColor();		//输出 "red"

使用 this 的原因
为什么使用 this 呢?因为在实例化对象时,总是不能确定开发者会使用什么样的变量名。使用 this,即可在任何多个地方重用同一个函数。请思考下面的例子:

function showColor() {
  alert(this.color);
};

var oCar1 = new Object;
oCar1.color = "red";
oCar1.showColor = showColor;

var oCar2 = new Object;
oCar2.color = "blue";
oCar2.showColor = showColor;

oCar1.showColor();		//输出 "red"
oCar2.showColor();		//输出 "blue"
解决方案:工厂方式

要解决该问题,开发者创造了能创建并返回特定类型的对象的工厂函数(factory function)。

例如,函数 createCar() 可用于封装前面列出的创建 car 对象的操作:

function createCar() {
  var oTempCar = new Object;
  oTempCar.color = "blue";
  oTempCar.doors = 4;
  oTempCar.mpg = 25;
  oTempCar.showColor = function() {
    alert(this.color);
  };
  return oTempCar;
}

var oCar1 = createCar();
var oCar2 = createCar();

为函数传递参数
我们还可以修改 createCar() 函数,给它传递各个属性的默认值,而不是简单地赋予属性默认值:

function createCar(sColor,iDoors,iMpg) {
  var oTempCar = new Object;
  oTempCar.color = sColor;
  oTempCar.doors = iDoors;
  oTempCar.mpg = iMpg;
  oTempCar.showColor = function() {
    alert(this.color);
  };
  return oTempCar;
}

var oCar1 = createCar("red",4,23);
var oCar2 = createCar("blue",3,25);

oCar1.showColor();		//输出 "red"
oCar2.showColor();		//输出 "blue"
构造函数方式(与工厂函数不同)

创建构造函数就像创建工厂函数一样容易。第一步选择类名,即构造函数的名字。根据惯例,这个名字的首字母大写,以使它与首字母通常是小写的变量名分开。除了这点不同,构造函数看起来很像工厂函数。请考虑下面的例子:

function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function() {
alert(this.color);
};
}

var oCar1 = new Car(“red”,4,23);
var oCar2 = new Car(“blue”,3,25);

与工厂方式的比较
1 在构造函数内没有创建对象,而是使用this关键字。
2 使用new运算符构造函数时,在执行第一行代码前先创建一个对象,只有用this才能访问该对象。
3 存在问题:就像工厂函数,构造函数会重复生成函数,为每个对象都创建独立的函数版本。

原型方式

该方式利用了对象的 prototype 属性,可以把它看成创建新对象所依赖的原型。

这里,首先用空构造函数来设置类名。然后所有的属性和方法都被直接赋予 prototype 属性。我们重写了前面的例子,代码如下:

function Car() {
}

Car.prototype.color = “blue”;
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.showColor = function() {
alert(this.color);
};

var oCar1 = new Car();
var oCar2 = new Car();

1 首先定义构造函数(Car),里面无任何代码。
2 接下来,通过Car的prototype属性添加属性去定义Car对象的属性。
3 调用new Car()时,圆形的所有属性都被立即赋予要创建的对象,意味着所有Car实例存放的都是指向showColor()函数的指针。

可以使用instanceof运算符检查给定变量只想的对象的类型。eg
alert(oCar1 instanceof Car); //输出 "true"

原型方式的问题

原型方式实现了函数共享,但同时也带来了一些问题:
1 原型方式的构造函数没有参数,不能通过给构造函数传递参数来初始化属性的值。这意味着对象在创建后才能改变属性的默认值。
2 当属性指向的是对象时,该对象会被多个实例共享,eg

function Car() {
}

Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.drivers = new Array("Mike","John");
Car.prototype.showColor = function() {
  alert(this.color);
};

var oCar1 = new Car();
var oCar2 = new Car();

oCar1.drivers.push("Bill");
//由于drivers是引用值,这里Car的两个对象都指向同一个drivers数组。
alert(oCar1.drivers);	//输出 "Mike,John,Bill"
alert(oCar2.drivers);	//输出 "Mike,John,Bill"
箭头函数

箭头函数的一个用处是简化回调函数。

// 正常函数写法
[1,2,3].map(function (x) {
  return x * x;
});

// 箭头函数写法
[1,2,3].map(x => x * x);
另一个例子是

// 正常函数写法
var result = values.sort(function (a, b) {
  return a - b;
});

// 箭头函数写法
var result = values.sort((a, b) => a - b);

2018.10.26
剩余语法(Rest parameter syntax)和展开语法(spread syntax)

Rest parameter syntax

The rest parameter syntax allows us to represent an indefinite number of arguments as an array.

demo
function myFun(a, b, ...manyMoreArgs) {
  console.log("a", a); 
  console.log("b", b);
  console.log("manyMoreArgs", manyMoreArgs); 
}

myFun("one", "two", "three", "four", "five", "six");

// Console Output:
// a, one
// b, two
// manyMoreArgs, [three, four, five, six]

myFun("one", "two", "three");

// a, one
// b, two
// manyMoreArgs, [three]
Spread syntax

Spread syntax allows an iterable such as an array expression or string to be expanded in places where zero or more arguments (for function calls) or elements (for array literals) are expected, or an object expression to be expanded in places where zero or more key-value pairs (for object literals) are expected.

demo
For function calls:

myFunction(...iterableObj);
For array literals or strings:

[...iterableObj, '4', 'five', 6];
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值