const和let定义的区别,相同点都是局部作用域,都不能重复声明,推荐使用const,如果变量会改变值的话再使用let,因为const可以提醒我们这个不能被改变,const符合函数式变成,js编译器对const进行了优化,处理机制不同。

const定义的是内存中的块,如果定义的是对象,是可以修改的,但是如果是基本数据类型就不能修改了。

1. 解构模式,解构的内部变量是怎么声明的,前面是什么声明的就是什么声明的,如:

function test(){

  return {a: 123, b: 345};

}

const {a,b} = test();

这里的, a,b就是用const声明的

如果是数组是这种写法

const s = ['🍌', '🍊', '🍎'];

const [c, d, e] = s;

函数参数默认值,参数的解构,扩展运算符

2. 字符串新增的方法:

s.startsWith(), s.endsWith(),s.includes()....

解析字符串模版的方法,两个参数都是数组

const s = 'hello';

const e = 'world';

const c = test`foor ${s} ${e} bar`;  //加了()就是直接传的参数,没有第二个参数了

function test(strs, ...values){ //...扩展运算符

  console.log(values); //arr

  console.log(strs); //arr

}

 strs的值是: ["foor ", " ", " bar"]

0:"foor "

1:" "

2:" bar"

相当于中间的两个变量将字符串分割成了三部分

3. 数组新增的方法

Array.from(str| arguments)

...扩展运算符的应用

const s = 'dfhajf';

const arr = Array.from(s);

const arr1 = [1,2,...s];

4. 对象

支持变量为key值,用 [ ] 包裹

Object.assign(),

属于浅拷贝,将属性合并到第一个对象上,复制对象:

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
var o1 = { a: 1, b: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };

var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

属性会被后续参数中的相同属性覆盖。

下面是深拷贝的例子

obj1 = { a: 0 , b: { c: 0}};
let obj3 = JSON.parse(JSON.stringify(obj1));
obj1.a = 4;
obj1.b.c = 4;
console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}

Object.assign()拷贝的是可枚举的属性,原型链中的属性和不可枚举的属性不能拷贝

原始类型会被包装成对象,根据自身的可枚举属性,如果不可枚举则不会被拷贝

var v1 = 'abc';
var v2 = 10;
var v3 = Symbol('foo');
var obj = Object.assign({},v1, v2, null, undefined, v3);
//null 和undefined会被忽略
//只有字符串的包装对象有可枚举属性
console.log(obj);
// {0: a, 1: b, 2: c}

异常会打断后续拷贝任务,比如遇到只读属性的时候,

var target = Object.defineProperty({},'foo',{
            value: 1,
            writable: false
        })
Object.assign(target, {bar:2},{foo2: 3,foo: 2, foo3: 4},{baz: 4});
console.log(target);

字面量的对象通过__proto__可以修改prototype的值

const drink = {

  getDrink(){

    return "pijiu"

  }

}

const sunday = {

  __proto__: drink,

}

Object.setPrototypeOf(sunday, drink);   //和上面的代码等价

sunday.getDrink();

上面可以看成是继承,Sunday继承drink中的属性和方法,如果sunday想在内部调用drink中的话

继承 用super

 

Object.is() 判断两个值是不是相等

Object.is(NaN, NaN)  //true

 

 

类的声明(class),es6实现了类的语法糖,但是和之前的声明还是有区别,区别是:

a. 类的声明不会存在提升,相当于使用let和const声明的,真正执行语句之前,它们会一直存在与临时死区中;

b. 类中的所有方法都是不可枚举的,在之前的声明中没有这个限制,只有通过Object.defineProperty(obj, "name", {value: '99', enumerable: false})定义的方法才会是不可枚举的

c. 类的名称在声明的内部是不可修改的,在外部可以,因为在内部相当于用const声明的类名,而在外部相当于用let声明的名字

d. 类的声明只能通过new调用,普通调用会报错,因为每个类都含有一个名为[[Construct]]的内部方法,通过关键字new调用那些不含有[[Construct]]的方法会报错;

e. 类声明中所有的代码自动运行在严格模式下,而且无法强行脱离严格模式

class Person{
    constructor(name){
        this.name = name;
    }
    sayName(){
        console.log(this.name)
    }
}
let man = new Person('xx');
man.sayName();

下面是通过其他方式实现的,可见代码量的区别

let Person2 = (function(){
    "use strict"
    const Person2 = function(name){
        if(typeof new.target === 'undefined'){
            throw new Error("必须通过关键字new调用构造函数");
        }
        this.name = name;
    }
    Object.defineProperty(Person2.prototype, 'sayName',{
        value: function(){
            if(typeof new.target !== 'undefined'){
                throw new Error("不可使用关键字new调用该方法");
            }
            console.log(this.name)
        },
        enumerable: false,
        writable: true,
        configurable: true
    })
    return Person2;
})();
let woman = new Person2('ccc');
console.log(woman.sayName());

需要重点理解这个自执行函数,class是顺序执行的,并不是new的时候才会调用,所以如果方法名或属性名是变量的话,在类声明下面再修改的话也不会生效了,使用的是类前面的值

new操作符的执行过程

1. 一个继承自prototype的新对象被创建,通过__proto__属性指向原型对象(prototype)

2. 使用指定的参数调用构造函数 (函数的名字),并将this绑定到新创建的对象

3. 由构造函数返回的对象就是new表达式的结果,如果构造函数没有返回值的话,就使用第一步的对象(一般情况下,都没有返回值,如果用户想返回不同的对象可以自己定义,如果返回的不是对象呢,而是基本的数据类型,则忽略不计,仍然使用第一步的对象)

 

理解原型对象,原型链

每创建一个新函数就会生成一个对应的原型对象,通过prototype属性连接,prototype中存储的是指针

原型对象中会有一个constructor属性,这个属性存储的也是一个指针,指向新函数,所以这是一个循环的过程

创建对象,继承对象的新方法,super是语法糖,原理还是原型链的继承,Object.create(newO, o.prototype) 

5. 函数

增加了一个fn.name

箭头函数,的this是父级的this。

函数参数,默认参数直接在形参中指定

this的指向

6. Iterator, Generator

Iterator是一个数据结构,需要有next()一步一步向下执行,和Generator函数结合使用

var fn = function *(){

  yield '22';

  yield '33';

}

const result = fn();

result.next();

result.next();

result.next();

 

co模块是什么东东

for of 是有Symbol.iterator属性的对象才能使用

for in 有什么问题

for in遍历数组的话  遍历顺序有可能不是按照数组的实际顺序,会遍历数组的所有属性,包括原型上新定义的

for of只是遍历数组的值,不包括原型上的,还有自定义的非索引值

 class类的定义,语法糖 

class Person{

  constructor(name){

    this.name = name;

  }

  sayName(){

    console.log(this.name)

  }

}

class Teacher extends Person{

  constructor(name){

    super(name);

  }

  sayName(){

    super.sayName();

    ...

  }

}

 

7. Set, Map

Set的方法

let arr = new Set('12444');

arr.add('33');

arr.add('34');

arr.has('1');

arr.delete('34');

for(let data of arr){

  console.log(data);

}

arr.clear();

console.log(arr.size)

Set可以直接去重,上面初始化的时候会生成 1 2 4,

Set是没有length属性的,有 size属性

Set没有key值,Map有key值,key值和value值可以是任何类型

Map的方法:

let map = new Map();

let fruit = {}, obj = function(){};

map.set(fruit,'32');

map.set( obj,'3233');

for(let item of map){

  console.log(item); //打印的是完整的一项

}

map.get(fruit);

map.size;

map.delete(fruit);

map.clear();

 

数组去重的方法

let arr = [1,3,4,5,1,2,3,4,5];

let result = [...new Set(arr)];

对于es6及之后的语法,可以转换成es5的查看实现过程,也叫原理

 

module的两种不同写法

a.

function test(){}

function gogo(){}

export test;

export gogo;

//export {test, gogo};

import {test, gogo} from 'index.js'

解构

b. 

export default {test, gogo}

import data from 'index.js'

data.test();

data.gogo();

 

8. async awite promise fetch

(async(){

  function promisefn(url){

    return new Promise(function(resolve, reject){

      $.ajax({

        url: url,

        success(res){

          resolve(res);

        },

        error(){

          reject('error');

        }

      })

    })    

  }

  const a1 = await promistfn('http://www.xxx.com/a');

  const a2 = await promistfn('http://www.xxx.com/b');

  let p = a1 + a2;

  console.log(p);

})

async await 也是通过promise对象来实现的。

 

修饰器 decorator

function testable(target){

  target.isTestable = true;

}

@testable

class myTestableClass{}

console.log(myTestableClass.isTestable);

修饰器对类的行为的改变,是代码编译时发生的,而不是运行时。这意味着,修饰器能在编译阶段运行代码

core-decorators.js库

 

浏览器有两个发请求的东西,一个是navigator.sendBeacon('a.php')做埋点用的,
一个是类ajax请求fetch('a.php')

 

symbol 唯一的

 

9. 数据类型

基本数据类型 6种了,Boolean,Number,String,null,undefined,Symbol

复杂数据类型统称为Object,新增的Set 和 Map 也是一个对象吧?

const obj = { name: 'www'};

obj.age = '333';  //不会报错,也就是可以添加,删除,修改属性值,但是不能改变对象的地址

obj = [];  //会报错

10. label statement  (语句优先)

 

11.自执行函数

操作符后面都是表达式

var b = 10;
(function b(){
b = 20;
console.log(b);
})();
console.log(b);

这个的运行结果想不通?

12.高阶函数,把函数当作参数或返回值的函数的函数

回调函数,闭包(函数,环境),惰性函数,柯里化(允许使用部分函数参数来生成函数),尾递归优化,反柯里化

ranmod

 

作用域的种类:

全局作用域,函数作用域,块级作用域(es6)

作用域链

变量与函数声明提前(变量提升)

this的指向,call,apply,bind

原型对象和原型链

构造函数的返回值,正常是不写返回值,但返回的是实例对象,特殊情况是写了返回值,return 简单的数据类型,返回的还是实例,如果返回的是对象类型,那返回的就是这个对象

if(!("userName" in window)){
var userName = 'zhengzheng.xz';
}
console.log(userName);  //undefined

变量提升

圆形对象中的constructor

Person.prototype.constructor === Person;

Function.prototype.constructor === Function;

Object.prototype.constructor === Object;

Object.constructor === Function; //这个是为什么呢

 

题:

var name = "global";

function A(name){

  alert(name);   //实参就是 变量赋值,相当于前面有一个var name  = name; 阻止了下面的变量提升,因为直接赋值了

  this.name = name;

  var name = '1';

}

A.prototype.name = '2';

var a = new A('3');

alert(a.name);

delete a.name;

alert(a.name);

 

function fun(n,o){

  console.log(o);

  return {

    fun: function(m){

      return fun(m,n);

    }

  }

}

var a = fun(0);

a.fun(1);

a.fun(2);

var b = fun(0).fun(1).fun(2).fun(3);

var c = fun(0).fun(1);

c.fun(2);

c.fun(3);

 

posted on 2018-04-16 15:50  Phoebeli  阅读(214)  评论(0编辑  收藏  举报