记录一些自己在学习es6的心得和笔记。补充一些关于es6的面试题。

内容过长,慎点。

1. letconst

  • let声明的变量只在代码块中有效,块外访问报错!
  • 经典案例:for循环中用var和let的区别,异步打印i(var情况属于内存泄漏)
  • for循环中,let可以覆盖条件中的变量,相当于父子作用域问题
  • 没有变量提升,必须先声明后使用,否则报错
  • 不论父作用域是否存在x变量,只要子作用域使用了let x ,都必须先定义后使用,否则报错
  • 块作用域内重复声明变量,直接报错

面试题

为撒需要快作用域呢?
答案:1.上面讲的for循环内存泄漏;2. 内层变量可能会覆盖外层变量。见下面场景代码

1
2
3
4
5
6
7
8
9
10
var tmp = new Date();

function f() {
console.log(tmp);
if (false) {
var tmp = 'hello world';
}
}

f(); // undefined

  • 有了快作用域,不再需要IIFE(立即执行函数表达式(fn(i){})(i)),直接用大括号扩起来即可
  • 函数声明语句的行为类似于let,思考一下,联系上面
  • 块作用域必须有大括号,否则不是块作用域,类似:省略写法:if (true) let x = 1;
  • const 也是只在块作用域内有效
  • cosnt 使得变量指向内存地址不的改动。(ps:简单数据的值就保存在内存地址,引用型在内存地址中保存的是指针)
  • Object.freeze可以使对象内部属性也不能增删改,!!!!只能冻结一层!下面实现递归可以深层冻结

Object.freeze实现原理。

1
2
3
4
5
for(let key in obj){
Object.definedProperty(obj,p,{
wwriteable:false
})
}

Object.freeze实现完全(彻底)冻结原理。(原理这个东西,面试一半会问,真是写代码肯定是越少越好啊)
实际是将对象变得不可扩展,已有属性不可重写,Object.definedProperty()、Object.seal()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//es5
function littlefreeze(obj){
if(obj instanceof Object){
Object.seal(Object); //不能扩展、删除属性
}
for(let key in obj){
if(obj.hasOwnProperty(p)){
Object.definedProperty(obj,p,{
wwriteable:false
})
}
littlefreeze(obj[key]) // 如果没有这一步周
}
}
//es6
var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key, i) => {
if ( typeof obj[key] === 'object' ) {
constantize( obj[key] );
}
});
};

  • let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性
1
2
3
4
5
6
//在浏览器全局执行
let a = 123;
window.a //undefined

var b =1
window.b //1

2.解构赋值

  • 只有当一个数组成员严格等于undefined,默认值才会生效。

    1
    2
    3
    let [x = 1] = [null];
    x // null
    // null ===undefined return false
  • 默认值声明相当于let,如下报错

    1
    let [x=y,y=1] = []; //error:y is not defined
  • 对象的解构,不是按照顺序,而是按照相同属性名称 let { foo: baz } = { foo: 'aaa', bar: 'bbb' }

  • 继承的属性也可以取到
  • 已声明的变量,解构赋值要加括号,不论var、let、const
  • 声明语句都不能带圆括号,赋值语句模式不能带括号(理解)

    1
    2
    3
    4
    5
    [(b)] = [3]; // 正确
    ({ p: (d) } = {}); // 正确,p是模式,d是变量
    //
    let [(a)] = [1]; // 错误
    let {x: (c)} = {}; // 错误
  • 解构用途:赋值、遍历键值对、取值

3.字符串扩展

  • unicode 表示法,emmmmm这个用的比较少。
  • 模板字符串了解下:aaaaaa${变量}bbbbb
  • 标签模板功能,如下代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //简单的
    alert`123` === alert(123)

    //复杂的
    let a = 1;
    let b = 2;

    function shit(str,变量1,变量2,...){log一下}
    // 不添加参数,就不接收

一个简单的转译用户提交text的通用函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function SaferHTML(templateData) {
let s = templateData[0];
for (let i = 1; i < arguments.length; i++) {
let arg = String(arguments[i]);

// Escape special characters in the substitution.
s += arg.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");

// Don't escape special characters in the template.
s += templateData[i];
}
return s;
}
let sender = '<script>alert("abc")</script>'; // 恶意代码
let message = SaferHTML`<p>${sender} has sent you a message.</p>`;

message
// <p>&lt;script&gt;alert("abc")&lt;/sc

  • emmmm涉及到了好多unicode,不懂啊,暂时先放过
  • String.fromCodePoint()可以识别大于0xFFFF的字符
  • startsWith,endsWith,includes,

上面前两个方法es5写法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
String.prototype.startWith = function(str){
if(str==null||str==""||this.length==0||str.length>this.length){
return false;
}
if(this.substr(0,str.length == str)){
return true;
}else{
return false
}
return true;
}
String.prototype.endWith = function(str){
if(str==null||str==""||this.length==0||str.length>this.length){
return false;
}
if(this.substring(this.length - str.length) == str){
return true
}else{
return false
}
return true
}