在业务中呆久了,对新事物的敏感度会下降的。也许这在某些情况下看来是一种借口,但业务确实需要考虑实际的产出,不能轻易的说对某些浏览器的舍弃,对于某些技术的实践。需要考虑对用户的影响,一般业务要对新技术的实践需要做非常多的前期调研,在飞速发展的前端时代,很可能在等待技术成熟的过程中错过了尝试让技术成熟的机会,而我很想体验一下这个过程。
纯技术与业务各有各的优劣,我想趁年轻都尝试一下。来打击一下自己浮躁的心。
use strict
use strict:严格模式,ECMAscript 5添加的新特性。
严格模式的作用:
- 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
- 消除代码运行的一些不安全之处,保证代码运行的安全;
- 提高编译器效率,增加运行速度;
- 为未来新版本的Javascript做好铺垫。
严格模式下的代码更合理、更安全、更严谨。下面看一些例子说明严格模式与一般模式的区别。
首先是使用场景:
<!--在不同的脚本中,会让不同的脚本进入不同的模式-->
<script> "use strict"; console.log("这是严格模式。"); </script> <script> console.log("这是正常模式。"); </script>
// 在方法中有作用域的区别
function strict(){ "use strict"; return "这是严格模式。"; }
function notStrict() { return “这是正常模式。”; }
区别:
"use strict";
// 报错,v未声明
v = 1;
// 报错,i未声明 for(i = 0; i < 2; i++) {}
// 语法错误,禁止使用 with
with (o){}
// evel 的参数不再污染全局
var x = 2;
console.log(x); // 2
eval('var x = 5; console.log(x)'); // 5
console.log(x); // ? 严格模式下是2,非严格模式下是5
// 强化作用域的概念
var xxx = (function (){
return !this;
})();
console.log(xxx);
var xxx = (function (){
"use strict";
return !this;
})();
console.log(xxx);
// 禁止函数内部遍历调用栈
(function f1() {
f1.caller;
f1.arguments;
})()
// 禁止删除变量,但是还是能够删除属性
"use strict";
var x;
delete x; // 语法错误
var x = {
a: 1
}
delete x.a // 正常
// 禁止重名参数
function(a, a, b) {
return;
}
// 禁止八进制表示法,第一位数据为0时报错
var n = 0100;
// 不允许任何情况下对 arguments 进行赋值
arguments = 1;
// arguments不再追踪参数的变化
(function (a) {
a = 2;
console.log(a, arguments[0]);
})(1);
(function (a) {
"use strict";
a = 2;
console.log(a, arguments[0]);
})(1)
// 禁止使用保留字
function package(protected) {
var implements;
}
// 函数必须要声明在外部
if (true) {
console.log(123)
function f() {console.log(1)}
}
f()
for...of
可以遍历出值,不是键,
'use strict';
var arr = ["a", "b", "c", "d"];
for (let a of arr) {
console.log(a); // a、b、c、d
}
var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (let e of engines) {
console.log(e); // Gecko、Trident、Webkit
}
let
定义块级作用域用的,局部变量;
"use strict";
{
var a = 10;
let b = 20;
}
console.log(a) // 10
console.log(b) // ReferenceError: b is not defined
块级作用域不被外界所污染。
"use strict";
var a = 10;
let b = 10;
{
var a = 20;
let b = 20;
}
console.log(a) // 20
console.log(b) // 10
不会被申明提前
"use strict";
console.log(a); // undefined
console.log(b); // ReferenceError: b is not defined
var a = 10;
let b = 10;
同一块级作用域不允许被再次赋值
"use strict";
let a = 10;
let a = 10; // SyntaxError: Identifier 'a' has already been declared
const
申明真正意义上的常亮,不允许修改属性,不允许重新赋值,都会报错
"use strict";
const PI = 3.1415;
PI = 3; // TypeError: Assignment to constant variable
const PI = 3.1; // SyntaxError: Identifier 'PI' has already been declared
新的数据结构Set
Set数据结构类似于数组,但是成员的值都是唯一的,没有重复的值,Set本身是一个构造函数,用来生成Set数据结构。
这种数据结构提供如下集中方法:
- size:返回成员总数。
- add(value):添加某个值。
- delete(value):删除某个值。
- has(value):返回一个布尔值,表示该值是否为set的成员。
- clear():清除所有成员。
唯一性:
'use strict'
var s = new Set();
[2, 3, 5, 4, 5, 2, 2].map(function(item){
s.add(item);
})
console.log(s) // Set { 2, 3, 5, 4 }
可遍历:
'use strict'
var s = new Set();
[2, 3, 5, 4, 5, 2, 2].map(function(item){
s.add(item);
})
for(var i of s){
console.log(i); // 2 3 4 5
}
API使用:
'use strict'
var s = new Set();
[2, 3, 5, 4, 5, 2, 2].map(function(item){
s.add(item);
})
console.log(s.size); // 4
console.log(s.has(2)); // true
s.delete(2);
console.log(s.has(2)); // false
s.clear();
console.log(s); // Set {}
新的数据结构Map
Map数据结构类似于对象,就是一个键值对的集合,但是“键”的范围不限于字符串,甚至对象也可以当作键。
这种数据结构提供如下集中方法:
- size:返回成员总数。
- set(key, value):设置一个键值对。
- get(key):读取一个键。
- has(key):返回一个布尔值,表示某个键是否在Map数据结构中。
- delete(key):删除某个键。
- clear():清除所有成员。
可遍历:
'use strict'
var m = new Map();
m.set('name', 'karyn') // 键是字符串
m.set(23, 'age') // 键是数值
m.set(undefined, 'undefined') // 键是undefined
var hello = function() {
console.log('hello');
}
m.set(hello, 'Hello ES6!') // 键是函数
for(var b of m){
console.log(b)
}
// [ 'name', 'karyn' ]
// [ 23, 'age' ]
// [ undefined, 'undefined' ]
// [ [Function], 'Hello ES6!' ]
API使用:
'use strict'
var m = new Map();
m.set('name', 'karyn') // 键是字符串
m.set(23, 'age') // 键是数值
m.set(undefined, 'undefined') // 键是undefined
var hello = function() {
console.log('hello');
}
m.set(hello, 'Hello ES6!') // 键是函数
console.log(m) // Map { 'name' => 'karyn', 23 => 'age', undefined => 'undefined', [Function] => 'Hello ES6!' }
console.log(m.has('name')) // true
console.log(m.has('years')) // false
console.log(m.has(23)) // true
console.log(m.has(undefined)) // true
console.log(m.has(hello)) // true
m.delete(undefined)
console.log(m.has(undefined)) // false
console.log(m.get(hello)) // Hello ES6!
console.log(m.get('name')) // karyn
遍历器Iterator
遍历器Iterator是一种协议,任何对象都可以部署遍历器协议,从而使得for...of循环可以遍历这个对象。遍历器协议规定,任意对象只要部署了next方法,就可以作为遍历器,但是next方法必须返回一个包含value和done两个属性的对象。其中,value属性当前遍历位置的值,done`属性是一个布尔值,表示遍历是否结束。
类似于中间件的思想,提供一个next方法。调用next方法时从堆栈中取出对应的值,可以一直调用下去。
'use strict'
function makeIterator(array) {
let nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ? {
value: array[nextIndex++],
done: false
} : {
done: true
};
}
}
}
let it = makeIterator(['a', 'b']);
let value_a = it.next();
let value_b = it.next();
let value_c = it.next();
let value_d = it.next();
console.log(value_a.value, value_a.done); // a false
console.log(value_b.value, value_b.done); // b false
console.log(value_c.value, value_c.done); // undefined true
console.log(value_d.value, value_d.done); // undefined true
generator函数
根据上面的协议,就有了新的generator函数,可以实现函数的暂停。直接看例子吧
'use strict'
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
}
var hw = helloWorldGenerator();
console.log(hw.next()) // { value: 'hello', done: false }
console.log(hw.next()) // { value: 'world', done: false }
console.log(hw.next()) // { value: undefined, done: true }
console.log(hw.next()) // { value: undefined, done: true }
函数体执行之后会在有yield的地方暂停,暂停之后只有主动调用next时才会继续执行。执行顺序如下。
'use strict'
function* f() {
console.log(1)
for (var i = 0; true; i++) {
var reset = yield i;
console.log(reset)
if (reset) {
i = -1;
}
}
}
var g = f();
console.log(0)
g.next() // { value: 0, done: false }
console.log(2)
g.next() // { value: 1, done: false }
console.log(3)
g.next(true) // { value: 0, done: false }
Class
ES6提供了“类”(class)。此前,一般用构造函数模拟“类”。
老式的写法
'use strict';
// ES5
let People = function(name) {
this.name = name;
};
People.prototype.sayName = function() {
return '我是' + this.name;
};
let person = new People('karyn');
console.log(person.sayName())
新的写法
'use strict';
// ES6
class People {
constructor(name) {
this.name = name;
}
sayName() {
return '我是' + this.name;
}
}
let person = new People('karyn');
console.log(person.sayName()) // 我是karyn
继承的实现
class HandsomeBody extends People {
constructor(name) {
super(name); // 执行父类 constructor
}
sayName() {
return super.sayName() + ',帅气如我'; // 调用父类的方法
}
sayHi() {
return '帅气'
}
}
let personB = new HandsomeBody('karynsong');
console.log(personB.sayName()) // 我是karynsong,帅气如我
console.log(personB.sayHi()) // 帅气