ES6 语法

本文深入解析ES6的新增特性,包括let与const变量声明、解构赋值、字符串、数值、对象、数组、函数、类、模块、Promise、async函数等核心概念,以及数据类型、Proxy与Reflect、Generator函数的使用技巧。
摘要由CSDN通过智能技术生成

ES6 语法


ES6,全称ECMAScript6.0,是JavaScript的下一个版本标准,2015.06发版。

JavaScript其实是Orcale公司注册的商标。因此JavaScript正式名称是ECMAScript

1. let 与 const
  • let

    • 声明的变量只在其命令所在的代码块内有效。

    • 不能重复声明同一个变量

    • 不存在变量提升

    {
    	let a=0;
      console.log("a=%d",a);   //a=0
    }
     console.log("a=%d",a);    //错误,变量a只在{}代码块内有效
    
  • const

    • 声明只读变量,声明之后必须初始化且不允许改变,全局有效。
2. 解构赋值

是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。是对赋值运算符的扩展。

  • 数组模型解构(Array)

    //基本数组解构
    let numbers = [1,2,3];
    //将数组numbers解构对其中的变量赋值到a,b,c上
    let [a,b,c] = numbers;
    console.log('a=%d;b=%d;c=%d',a,b,c);   //a=1;b=2;c=3
    
    //可忽略解构元素
    let numbers = [1,2,3];
    let [a,,c] = numbers;
    console.log('a=%d;c=%d',a,b,c);        //a=1;c=3
    
    //嵌套数组解构
    let numbers = [1,[2,3],4];
    let[a,[b],c];
    console.log('a=%d;b=%d;c=%d,',a,b,c);  //a=1;b=2;c=4
    
    
    //不完全解构
    let numbers = [1];
    let[a,b] = numbers;
    console.log('a=%d;b=%d',a,b);  //a=1;b=undefined    
    
    //解构默认值(当解构赋值有匹配结果,且解构为[undefined]时,会触发默认值作为返回结果)
    let numbers = []; //或 let numbers = [undefined];
    let[a=5] = numbers;
    console.log('a=%d',a);         //a=5        
    
    //剩余运算符
    let numbers = [1,2,3,4,5];
    let[a,...b] = numbers;
    console.log('a=%d;b=%o',a,b);  //a=1;b=[2,3,4,5]
    
    //字符串等(在数组解构中,解构目标若为可遍历对象,皆可进行解构赋值。即可遍历的对象要实现Iterator接口)
    let [a,b,c,d,e,f] = 'hello';
    consolo.log('a=%s,b=%s,c=%s,d=%s,e=%s',a,b,c,d,e);
    
  • 对象模型解构(Object)

    //基本对象解构
    let person = {name:'zcmain',age:20};
    let{name,age} = person;
    console.log('name=%s,age=%d',name,age);  //name=zcmain,age=20
    
    //嵌套对象解构
    let School = {schoolName:'上海第一中学',Class:{className:'高三(1)班',students:35}};
    let {schoolName,Class:{className,students}} = School; 
    console.log('schoolName=%s,classname=%s,students=%d',schoolName,className,students); 
    //schoolName=上海第一中学,className=高三(1)班,studnts=35
    
    //忽略解构对象
    let p = {p1:['hello',{p2:'world'},'gooBey']};
    //忽略对象内部数组中的对象
    let {p1:[x,,y]} = p;  //或者let {p1:[x,{},y]} = p;
    console.log('x=%s,y=%s',x,y);
    
    //不完全解构对象
    let School={class:['高三(1)班','高三(2)班']};
    let {class:[class1,class2,class3]} =School;
    console.log('class1=%s,class2=%s,class3=%s',class1,class2,class3);
    //class1=高三(1)班,class2=高三(2)班,class3=undefined
    
    //剩余运算符
    let {a,b,...rest} = {a:10,b:20,c:30,d:40}
    console.log('a=%s,b=%s,c=%o',a,b,c);
    //a=10,b=20,rest={c:30,d:40}
    
    //解构默认值
    let {a=10,b=5} = {a:3};
    console.log('a=%d,b=%d',a,b);
    //a= 3,b=5
    
3. ES6字符串
  • 字符串识别

    之前判读是否包含子串,ES6之前用indexOf,ES6新增如下三个方法

    • includes():返回布尔类型,判断是否找到参数字符串。
    • startsWith():返回布尔类型,判断参数字符串是否在原字符串头部。
    • endsWith():返回布尔类型,判断参数字符串是否在原字符串尾部。

    以上三个方法都可以接受两个参数,即后一个参数为要搜索的字符串和可选搜索起始位置索引。

    注意:如果要知道字串位置,还得需要使用indexOflastIndexOf

  • 字符串重复

    repeat(number)返回新的字符串,number表示字符串重复次数

    • number是小数则向下取整
    • number是负数则报错
    • number是0~-1之间小数,会取整为-0,等同于repeat零次
    • number是NaN等同于repeat零次
    • number是数字字符串,先将其转换为数字,否则等同于repeat零次
    let hello = "Hello";
    
    hello.repeat(3.2);
    //hello,hello,hello
    hello.repeat(-0.5);
    //""
    hello.repeat(NaN);
    //""
    hello.repeat("sdf");
    //""
    hello.repeat("2");
    //hello,hello
    
  • 字符串补全

    • padStart(int,string):返回新字符串,表示用指定字符串从原字符串头部(左侧)补齐生成指定长度的新字符串
    • padEnd(int,string):返回新字符串,表示用指定字符串从原字符串尾部(右侧),补齐生成指定长度的新字符串。

    注意

    • 第一个参数:指定生成字符串的最小长度。
    • 第二个参数:用来补全的字符串,如果没有指定,默认用空格填充。
    • 如果指定长度小于或者等于原字符串长度,则返回原字符串。
    • 如果原字符串加上补全的字符串大于指定长度,则截去超出位数的补全字符串。
    let h = "h";
    h.padStart(3,'0');
    //00h
    h.padEnd(5,'e');
    //heeee
    
  • 字符串模版

    • 字符串中插入变量表达式

      let name = 'zcmain';
      let age = 20;
      let content = "Hello,My name is ${name},I am ${age+1} years old next year.";
      
    • 字符串中调用函数

      add=(a,b)=>{
      	return a+b;
      }
      let content = "get sum ${add(2,3)}";
      
4. 数值
  • 将给定的字符串转换为指定的进制整数

    //不指定进制,默认转换为十进制
    Number.parseInt('12.24');    //12
    
    Number.paraseInt("0010",2);  //2
    
  • 判断给定的参数是否为整数

    Number.isInteger(1);    //true
    Number.isInteger(1.1);  //false
    Number.isInteger("20")  //false
    
  • 判断给定的数值是否在安全范围内

    Number.isSafeInteger(Number.MAX_SAFE_INTEGER-1); //true
    
  • Math对象扩展

    普通计算

    • Math.cbrt:计算一个数的立方根

      Math.cbrt(8);     //2
      Math.cbrt("8");   //2,会对非数值进行转换
      Math.cbrt("hhh"); //NaN
      
    • Math.imul:乘法(32位有符号整数)

      //1与2相乘结果;等同于 a*b
      Math.imul(1,2);  //2
      
    • Math.hypot:计算所有参数的平方和的平方根

      Math.hypot(3,4);     //5=√25 (3*3 + 4*4)
      Math.hypot(2,4,5,'6'); //9=√81 (2*2 + 4*4 + 5*5 + 6*6)
      

    数字处理

    • Math.trunc:返回数字的整数部分

      console.log(Math.trunc(12.34));        //12
      console.log(Math.trunc("-3.1415926")); //-3
      console.log(Math.trunc("3.1415926"));  //3
      
    • Math.sign:判断数值的符号(正、负、0)

      Math.sign(5);    //1
      Math.sign(-5);   //-1
      Math.sign(0);    //0
      Math.sign(-0);   //-0
      Math.sign('5');  //1
      Math.sign('-5'); //-1
      
5. 对象

ES6允许对象的属性直接写变量,此时属性名默认为变量名,属性值为变量值

const name='zcmain';
const age = 20;
const person={name,age};
//等同于
const person={name:name,age:age}
  • 对象的扩拓展运算符

    拓展运算符...用于取出参数对象所有可能遍历属性然后拷贝到当前对象

    基本用法

    let person={name:'zcmain',age:20};
    //使用拓展运算符,将perosn对象中所有属性拷贝到someone对象中
    let someone = {...person}; 
    //someone = {name:'zcmain',age:20}
    

    可用于合并两个对象

    let name = {name:'zcmain'};
    let age = {age:20};
    let person = {...name,...age};
    //person = {name:'zcmain',age:20}
    

    注意

    • 自定义的属性在拓展运算符后面,则拓展运算符对象内部同名的属性将被覆盖掉

      let userName={name:'zcmain'};
      let userAge={age:20};
      //自定义的属性name覆盖了前面拓展运算符userName对象中的name属性
      let person = {...userName,...userAge,name:'Tom'};
      //person={name:'Tom',age:20}
      
  • 对象新方法

    Object.assign:用于将源对象中所有属性复制到目标对象中

    第一个参数是目标对象,后面参数为源对象

    注意:

    • 如果目标对象和源对象有同名属性,或者多个源对象有同名属性,则后面的会覆盖前面的属性。
    • 如果函数只有一个参数,当参数不为对象时,先将参数转换为对象然后返回。
    • assign的属性是浅拷贝(地址引用),改变目标对象中属性,源对象也会同步被更改
    let target = {a:0};
    let sour1 = {b:1};
    let sour2 = {c:2};
    Object.assgin(target,sour1,sour2);
    //target={a:0,b:1,c:2}
    

    Object.is:用来比较两个值是否严格相等,与===类似

    与===区别

    Object.is(+0,-0);  //false
    +0 === -0          //true
    
    Object.is(NaN,NaN); //true
    NaN === NaN         //false
    
6. 数组与集合
数组(Array)
  • 数组新创建

    Array.of()

    //类型可为不同类型
    Array.of(1,2,3,'4',true,);   //[1,2,3,4]
    
    //参数为空,返回空数组
    Array.of();   //[]
    
    
  • 从一个可迭代对象创建数组(返回转换后的数组)

    Array.from(arrayLike[,mapFn[,thisArg]])

    参数详解:

    • arrayLike:想要转换的类数组对象或可迭代对象。
    • mapFn(可选):map 函数,用于对每个元素进行处理,放入数组的是处理后的元素。
    • thisArg(可选):用于调用指定 map 函数执行时的 this 对象

    举个🌰

    声明可遍历arrayLike

    //声明arrayLike数组
    let arrayLike = [1,2,3,4];
    //参数为数组,返回与原数组一样的数组
    let array = Array.from(arrayLike);
    //[1,2,3,4]
    

    指定mapFn函数

    注意:如果thisArg不为空,则不可以用箭头函数,否则内部的this会指向window

    let array = Array.from(arrayLike,(value)=>{
      //指定mapFn函数,对原始数组每个元素进行乘2处理
      return Math.imul(value,2);
    });
    //[2,4,6,8]
    

    指定thisArg参数,用于指定 map 对象函数执行时的 this 对象

    注意:mapFn不可以使用箭头函数,否则内部的this会指向window

    //定义一个map对象
    let map={
        //声明fun方法
        fun:(value)=>{
          return Math.imul(value,2);
        }
    }
    //这里mapFn不可以使用箭头函数
    let array = Array.from(arrayLike,function(value){
      //通过this调用map对象内的fun函数
      return this.fun(value);
    },map);  //指定对象
    
  • 转换可迭代对象

    map转换成为Array

    let map = new map();
    map.set('key0','value0');
    map.set('key1','value1');
    map.set('key2','value2');
    
    let array = Array.from(map);
    //[['key0','value0'],['key1''value1],['key2','value2']]
    

    Set转Array

    let set = new Set();
    set.add(1);
    set.add(2);
    set.add(3);
    
    let array = Array.from(set);
    //[1,2,3]
    

    字符串转换成Array

    let st = 'hello';
    let array = Array.from(str);
    //['h','e','l','l','o']
    
  • 扩展的方法

    • Find() :查找数组中符合条件的元素,若多个符合,返回第一个元素

      let array = Array.of(1,2,3,4);
      let result = array.find((item)=>{
          return item>2;  //如符合条件元素有: 3、4 ;这里返回第一个
      });
      //3
      
    • findIndex():数组中符合元素的索引,若多个符合,则返回第一个元素索引

      let array = Array.of('a','b','c','d','e','c');
      let result = array.findIndex((item)=>{
          return item === 'c';    //符合元素的下标有:2、5;这里返回第一个符合元素的下标
      })
      //2
      
    • fill():填充。将一定范围内的数组元素内容修改为指定的值

      第一个参数:用于填充的值

      第二个参数:被填充的起始索引

      第三个参数(可选):被填充的结束所以,默认为数组末尾

      let array Array.of('a','b','c','d','e');
      //把字符'hello',填充到数组的第二个元素和第三个元素之间[1,5)
      let result = array.fill('hello',1,5);
      //['a','hello','hello','hello','e']
      
    • copyWithin():将一定范围索引的数组元素修改为该数组另一指定范围索引的元素

      第一个参数:被修改的数组起始索引

      第二个参数:被用来覆盖的数组的起始索引

      第三个参数(可选):被用来覆盖数组的结束索引,默认为数组末尾

      let array = Array.of('a','b','c','d','e','f','g','h');
      //将当前数组下标为[0,2)范围内的元素,替换当前数组下标为3的元素后面对应长度的元素上
      let result = array.copyWithin(3,0,2);
      //['a','b','c','a','b','f','g','h']
      
    • 遍历

      键值对遍历(key(下标)-value)

      let array = Array.of('a','b',1,false,{},()=>{},'c',5);
      for(let [key,value] of array.entries()){
          console.log(key,value);
      }
      //0 a
      //1 b
      //2 1
      //3 false
      //4 {}
      //5 [Function]
      //6 c
      //7 5
      

      遍历key(下标)

      let array = Array.of('a','b',1,5);
      for(let key of array.keys()){
        console.log(key);
      }
      //0
      //1
      //2
      //3
      

      遍历值

      let array = Array.of('a','b',1,5);
      for(let value of array.values()){
        console.log(value);
      }
      //a
      //b
      //1
      //5
      
    • 嵌套数组转换一维数组

      flat():数组铺平(只会铺平一层)

      let array = Array.of(1,2,3,[4,5],6);
      let result = array.flat();
      //[1,2,3,4,5,6]
      

      flat(number):铺平多层

      let array = Array.of(1,2,3,[4,5,[6,7]],8);
      //flat()默认铺平一层
      let result = array.flat();
      //[1,2,3,4,5,[6,7],8]
      //指定flat(2)铺平两层
      let result = array.flat();
      //[1,2,3,4,5,6,7,8]
      

      flat(Infinity):全部铺平

      //嵌套了五层的数组,使用flat(Infinity)对其进行铺平转换为一维数组
      let array = Array.of(1,['a',[false,[{},[()=>{},['A']]]]]);
      let result = array.flat(Infinity);
      //[1,'a',false,{},[Function],'A']
      

      flatMap:先对数组中每个元素进行处理,然后再对返回值组成的数组进行铺平

      注意:flatMap()只能展开一层数组。多层则出现NaN

      let array = Array.of(1,2,3,[4]);
      //flatmap相当于对源数组进行乘2处理后,返回值组成的新数组[2,4,6,[8]]进行一次平铺
      let result = array.flatMap((value)=>{
            return Math.imul(value,2);
      });
      //[2,4,6,8]
      
      //flatMap降维多层嵌套数组失败
      let array2 = Array.of(1,2,3,[4,[5]]);
      let result2 = array.flatMap((value)=>{
            return Math.imul(value,2);
      });
      //[ 2, 4, 6, NaN ]
      
      
  • 数组复制与合并

    • 数组复制

      let array1 = Array.of(1,2,3,4);
      let array2 = [...array1];
      //[1,2,3,4]
      
    • 数组合并

      let array1 = Array.of(1,2,3);
      let array2 = Array.of(4,5);
      let array = [...array1,...array2];
      //[1,2,3,4,5]
      
  • 数组缓冲区

    数组缓冲区市内存中的一段地址,实际字节数在创建时确定,之后可修改内容,不可修改数组大小

    • 创建数组缓冲区

      //创建字节长度为10的数组缓冲区
      let arrayBuffer = new ArrayBuffer(10);
      console.log(arrayBuffer.byte.Length);
      //10
      
集合(Map & Set)

Map

  • Map的键可以是任意值:字符串对象函数NaN

    //key是字符串
    let map = new Map();
    let strKey = 'Key';
    map.set(strKey,"字符串key对应的value");
    let value = map.get(strKey);   //字符串key对应的value
    
    //key是对象
    let map = new Map();
    let objKey = {};
    map.set(objKey,"对象类型key对应的value");
    let value = map.get(objKey);  //对象类型key对应的value
    let value2 = map.get({});     //undefined,因为objKey !== {}
    
    //key是函数
    let map = new Map();
    let funKey = function () {};
    map.set(funKey,"函数类型的key对应的value");
    let value = map.get(funKey);        //函数类型的key对象的value
    let value2 = map.get(function(){})  //undefined,因为funKey !== function(){}
    
    //key是NaN
    let map = new Map();
    let nanKey = NaN;
    map.set(nanKey,"NaN类型的key对应的value");
    let value = map.get(nanKey);  //NaN类型的key对应的value
    let value2 = map.get(NaN);    //NaN类型的key对应的value
    //虽然 NaN 和任何值甚至和自己都不相等(NaN !== NaN 返回true),NaN作为Map的键来说是没有区别的。
    
  • Map迭代遍历 for...of forEach()

    • for...of

      //迭代遍历输出map中的key-value
      let map = new Map();
      map.set("key1","a")
      map.set("key2","b");
      for(let [key,value] of map){   // for(let [key,value] of map.entries)
        console.log('key->%s;value->%s',key,value);
      }
      //key->key1;value->a
      //key->key2;value->b
      
      //迭代输出key
      let map = new Map();
      map.set("a",0);
      map.set("b",1);
      for(let key of map.keys){
        console.log('key->%s',key);
      }
      //key->a
      //key->b
      
      //迭代输出value
      let map = new Map();
      map.set("a",0);
      map.set("b",1);
      for(let value of map.values()){
        console.log('value->%s',value);  
      }
      //value->0
      //value->1
      
    • forEach()

      let map = new Map();
      map.set("a",0);
      map.set("b",1);
      //使用forEach遍历map中key-value
      map.forEach((key,value)=>{
        console.log('key->%s;value->%s',key,value);
      })
      //key->a;value->0
      //key->b;value->1
      
  • Map对象操作:转换克隆合并

    • Map 与 Array转换

      map构造函数可以将一个二维键值对数组转换成一个Map对象

      //二维键值对数组————转换为Map
      let array = [["key1","value1"],["key2","value2"],["key3","value3"]];
      let map = new Map(array);
      
      //使用Array.from函数可以将一个Map转换为一个二维键值对数组
      let map = new Map();
      map.set("a",0);
      map.set("b",1);
      map.set("c",2);
      map.set("d",3);
      let array = Array.from(map);
      //array1=[["a",0],["b",1],["c",2],["d",3]]
      
    • Map合并

      合并两个Map对象时,如果有重复的键值,后面会覆盖前面的

      //合并数组
      	let map1 = new Map([["a",0],["b",1]]);
      	let map2 = new Map([["a",5],["b",0],["c",8]]);
      	//合并两个map
      	let mergeMap = new Map([...map1,...map2]);
      	mergeMap.forEach((value,key)=>{
      		console.log('key->%s,value->%s',key,value);
      	})
      	//{a:5,b:0,c:8}
      

Set

Set集合对象允许存储任何类型的唯一值,无论是原始值还是对象引用

  • 存储

    let set = new Set();
    	set.add(1);
    	set.add(2);
    	set.add(2);   //相同的值只能存储一个,唯一性!
    	set.add("a");
    	set.add(false);
    	set.add(()=>{});
    	set.add({});
    	for(let value of set){
    		console.log(value);
    	}
    //1
    //2
    //a
    //false
    //[Function]
    //{}
    
  • Set迭代遍历

    let set = new Set();
    	set.add(1);
    	set.add(2);
    	set.add(2);   //相同的值只能存储一个,唯一性!
    	set.add("a");
    	set.add(false);
    	set.add(()=>{});
    	set.add({});
      set.add(['a','b','c']);
      set.forEach((value)=>{
      	console.log("value=%s",value);
      });	
    //value=1
    //value=2
    //value=a
    //value=false
    //value=()=>{}
    //value={}
    //value=[ 'a', 'b', 'c' ]
    
  • 类型转换

    Array 转 Set (使用Set构造函数)

    //使用Set构造函数将Array转为Set
    let array = [1,2,3,4,5,6,7,8];
    let set = new Set(array);
    //{1,2,3,4,5,6,7,8}
    

    Set 转 Array(使用拓展运算符…操作符号)

    //使用...操作符将Set转换为Array
    let array = [...set];
    //[1,2,3,4,5,6,7,8]
    
    //或者使用Array.from(set);进行转换
    let array = Array.from(set);
    

    String 转 Set(使用Set构造函数)

    //使用Set构造函数将String转换为Set,注意Set.toString方法不能将Set转为String
    let str = 'hello';
    let set = new Set(str);
    //{h,e,l,l,o}
    
  • Set对象作用

    • 数组去重

      let array = [1,2,3,3,4,5,5,5,6,7];
      let set = new Set(array);
      //{1,2,3,4,5,6,7}
      
    • 合并Set

      let set1 = new Set([1,2,3]);
      let set2 = new Set([4,3,2]);
      let mergeSet = new Set([...set1,...set2])
      //{1,2,3,4}
      
    • 获取交集

      let set1 = new Set([1,2,3]);
      let set2 = new Set([4,3,2]);
      let set = new Set([...set1].filter((x)=>{
        //返回set2里面包含set1的元素
        return set2.has(x);
      }));
      //{2,3}
      
    • 获取差集

      let set1 = new Set([1,2,3]);
      let set2 = new Set([4,3,2]);
      let set = new Set([...set1].filter((x)=>{
        //返回set2里面不包含set1的元素
        return !set2.has(x);
      }));
      //{1}
      
7. 函数(箭头函数)
  • 基本用法

    • 默认参数

      //声明函数
      function fn(name,age=20){
        console.log(name,age);
      }
      
      //调用函数
      fn('zcmain',30); //zcmain,30
      fn('zcmain',''); //zcmain
      fn('zcmain');    //zcmain,20 ;使用默认参数(只有在未传递参数,或者参数为undefined才会使用默)
      

      注意:使用函数默认参数时,不允许有同名参数

      //不报错
      function fn(name,name){
         //TODO...
      }
      //错误!!!使用函数默认参数,出现了同名参数name
      function fn(name,name,age=20){
        //TODO...
      }
      
    • 不定参数

      不定参数用来表示不确定参数个数,形如:...变量名,由...加上一个具体名参数标识符组成。具名参数只能放在参数组的最后,并且有且只有一个不定参数。

      基本用法

      //定义不定参数的函数
      function fn(...params){
        console.log(params.length);
      }
      
      //调用不定参数的函数
      fn(1,2)       //2
      fn(1,2,3,4);  //4
      
  • 箭头函数

    箭头函数,提供了一种更加简洁的函数书写方式,基本语法参数=>函数体

    • 基本用法

      let fun = v=>v*2;
      //等价于
      let fun = function(v){
        return v*2;
      }
      fun(1); //2
      
    • 无参或多参用()括起来参数

      无参箭头函数

      //无参箭头函数,用()括起
      let fun = ()=4;
      //等价于
      let fun1 = function(){
          return 4;
      }
      fun1();  //4
      

      多参箭头函数

      //多个参数箭头函数用()括起参数
      let fun = (a,b,c)=> a+b+c;
      //等价于
      let fun = function(a,b,c){
        return a+b+c;
      }
      
      fun(1,2,3); //6
      
    • 函数体有多行语句用{}括起来

      箭头函数函数体有多行语句,用{}包裹起来,表示代码块,当只有一行语句,并且需要返回结果时,可以省略{},结果会自动返回。

      //函数体有多行,用{}括起函数体
      let fun = (a,b)=>{
         let result = a+b;
         return result;
      }
      fun(2,5); //10
      
    • 返回对象也要用{}将对象包裹起来,为了区分于代码块

      //报错
      let fun = ()=>{id:1,name:'zcmain'};
      
      //不报错
      let fun = ()=>{{id:1,name:'zcmain'}};
      
    • 没有thissuperargumentnew.target绑定

      let fun = ()=>{
        //箭头函数内没有this对象,此时的this是外层的this对象,即window
         console.log(this);
      }
      

      箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象。

      每个函数都包含两根非继承而来的方法:

      function fn(){
        setTimeout(()=>{
          // 定义时,this 绑定的是 fn 中的 this 对象
          console.log(this.a);
        },0)
      }
      var a = 20;
      /**
       *apply()和call()。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的
       *值。
       *fn 的 this 对象为 {a: 19}
       */
      fn.call({a: 18});  // 18
      

      不可以作为构造函数,也就是不能使用 new 命令,否则会报错

      扩展《javascript 中函数调用方法:apply() 和 call()

8. 迭代器(Iterator)

Iterator迭代器是ES6引入的一种新的遍历机制

可迭代的数据结构

  • Array
  • String
  • Map
  • Set
  • Dom元素(正在进行中…)

1. 数组迭代

数组(Array)和类型数组(TypeArray)他们是可迭代的

let array = Array.of(1,2,3,4,5);
//迭代数组元素
for(let value of array){
  console.log(value);
}
//1
//2
//3
//4
//5

//迭代数组下标和元素index-value
for(let [index,value] of array.entries()){
  console.log(index,value);
}
//0,1
//1,2
//2,3
//3,4
//4,5

2. 字符串迭代

字符串可迭代,他们遍历的是Unicode码,每个码可能包含一到两个JavaScript字符

let str = 'hello';
for(let value of str){
     console.log(value);
}
//h
//e
//l
//l
//o

3. 迭代Map

Map主要迭代他们的entries,每个entry都会被编码为[key,value]的项,entries是以确定形式进行迭代,顺序与添加顺序相同

注意:WeakMaps不可迭代

let map = new Map();
map.set('a',1);
map.set('b',2);
map.set('c',3);
map.set('d',4);

//遍历key-value
for(let [ky,value] of map){
  console.log(key,value);
}
//a,1
//b,2
//c.3
//d,4

//只遍历key
for(let key of map.keys()){
  console.lo(key);
}
//a
//b
//c
//d

//只遍历value
for(let value of map.values()){
  console.log(value);
}
//1
//2
//3
//4

4. 迭代Set

Set是对其元素进行迭代,迭代顺序与其添加顺序相同

注意:WeakSet不可迭代

let set = new Set();
set.add('Zcmain');
set.add('Tom');
set.add('Judy');
//遍历set 元素
for(let value of set){
  console.log(value);
}
//Zcmain
//Tom
//Judy

说明

  1. 使用for…of进行遍历

    • 如果使用letconst,每次迭代将会创建一个新的存储空间,这可以保证作用域在迭代内部

      let array = Array.of(1,2,3,4,5);
      for(let value of array){
           console.log(value);
      }
      console.log(value);   //错误,value为let修饰变量,只在for...of循环作用域内有效
      
    • 如果使用var会作为全局,迭代每次不会创建一个新的存储空间

      let array = Array.of(1,2,3,4,5);
      for(var value of array){
           console.log(value);
      }
      console.log(value);   //正确访问value,value是通过var修饰为全局变量
      
9. ES6 Class类

在ES6中,class类作为对象的模版被引入,可以通过class关键字定义类。class的本质是function

注意要点

  • 类不可重复声明
  • 类必须被调用前进行定义,否则会报错
  • 类中方法不需要function关键字
  • 方法之间不能加分号

1. 类声明

//声明Person类
class Person{
     constructor(name){
       this.name = name;
     }
}
//声明User类
class User{
  constructor(age){
    this.age= age;
  }
}

2. 类的定义

类表达式可以为匿名或命名

//类表达式——>命名类(声明时指定类的名称)
let person = class Person{
      //构造函数
      constructor(age){
      this.age = age
      }
 }

//类表达式——>匿名类(声明时不指定类名称)
let user = class{
    //构造函数
    costructor(name){
      this.name = name;
    }
}

不可重声明/定义类

class Person{}
class Person{}     //错误,Person类已存在不可重复声明

let User = class{}
class User{}       //错误,Person类已存在不可重复声明

3. 类的主体

  • 属性

    • 静态属性

      静态属性:class类本身的属性,static修饰,不需要实例化。ES6规定class内部只有静态方法,没有静态属性

      class Person{
          //构造函数
         constructor(age){
           this.age = age;
         }
        
         //静态属性(Person类直接调用)
      	 static name = 'zcmain';
      
         //静态方法(Person类直接调用)
         static getName(){
            return this.name;
         }
        
         //实例方法(Person实例化后才可调用)
         getAge(){
           return this.age;
         }
      }
      
      //静态属性 & 静态方法 通过类名直接调用
      Person.name;         //zcmain
      Person.getName();    //zcmain
      
      //非静态方法,需要实例化对象后才可调用
      let person = new Person(20);
      person.getAge();     //20
      

      name类名属性(属于静态属性):返回跟在class 后的类名称(如果是非匿名类)

      class Person{
         constructor(){
         }
      }
      console.log(Person.name); // 通过类名.name返回class的名称(非匿名类)
      //Person
      
    • 实例属性

      实例属性:定义在实例对象(this)上的属性

      class Person{
           //实例属性
           age = 20;
           //实例方法
           getAge(){
             return this.age;
           }
      }
      let person = new Person();
      person.getAge();  //20
      
  • 方法

    • 构造方法

      constructor方法是类默认的方法,创建类的实例化对象时被调用

      //构造函数默认返回当前实例对象
      class User{
           constructor(){
             //默认返回this(User实例对象)
           }
      }
      console.log(new User() instanceof Test);     //true
      
      //指定构造函数返回实例对象
      class Person{
        constructor(){
          //指定返回User实例对象
          return new User();
        }
      }
      console.log(new Person() instanceof Person );  //false; 
      
    • 静态方法

      静态方法:class类本身的方法,static 修饰,不依赖于类的实例对象。

      class Person{
          static getName(){
            return 'zcmain';
          }
      }
      console.log(Person.getName());  //静态方法通过类直接调用,无需实例化类对象
      
    • 实例方法

      实例方法:定义在实例对象上的方法,依赖于类的实例化对象

      class Person{
            getName(){
              return 'zcmain';
            }
      }
      
      let person = new Person();
      console.log(person.getName());  //实例方法依赖于类的实例化对象
      
  • 类的实例化

    class的实例化必须通过**new**关键字

    class Person{}
    //通过new关键字实例化Person对象
    let person = new Person();
    
  • 封装于继承

    • getter/setter

      class Person{
         constructor(name,age){
           this.name = name;   //实例化时调用 set方法
           this.age = age;
         }
        
         set name(name){
           console.log('setter');
           this.name = name;   //自身递归调用(this.name = name赋值会触发name的set方法)
         }
         
         get name(){
           console.log('getter');
           return this.name;
         }
      }
      //不断输出setter,最终导致RangeError,如何优化?见下面解决方案
      let person = new Person('zcmain',20);  
      

      解决setter方法递归调用

      class Person{
          constructor(name,age){
            this.name = name;    //触发set name方法 将 name 赋值给this._name
            //或者
            //this._name = name; //不会触发set name方法,直接将name赋值给this._name
            this.age = age;
          }
        
          set name(name){
            console.log('setter');
            this._name = name;  //将 name 重复赋值给变量 this._name
          }
        
          get name(){
            console.log('getter');
            return this._name;
          }
      }
      
      let person = new Person('zcmain',20);
      console.log(person.name);   //内部调用getName()方法
      //或者
      console.log(person._name);  //直接访问_name变量,不调用getName方法
      //zcmain
      

      setter方法必须放在父类中或者同级出现(不可出现在子类中)

      1. getter放在父类中,setter放在子类中
      //将getter放在父类中
      class Person{
        constructor(name){
          this._name = name;
        }
        get name(){
          return this._name;
        }
      }
      
      //setter放在子类中
      class Man extends Person{
          constructor(name){
            super(name);
          }
        
          set name(value){
            this._name = name;
          }
      }
      
      let man = new Man('zcmain');
      console.log(man.name);       //undefined,不可正常访问
      
      1. setter放在父类中,getter放在子类中
      //setter放在父类中
      class Person{
        constructor(name){
          this._name = name;
        }
        set name(value){
          this._name = value;
        }
      }
      
      //getter放在子类中
      class Man extends Person{
          constructor(name){
            super(name);
          }
        
          get name(){
            return this._name;
          }
      }
      
      let man = new Man('zcmain');
      console.log(man.name);       //zcmain,可正常访问
      

      ps:setter/getter同级出现(同时放在父类或者自类中都可正常访问)

    • extends

      //类继承通过extends实现
      class Man extends Person{}
      
    • super

      //子类构造方法constructor中必须有super,且必须出现在this之前
      class Man extends Person{
          constructor(name){
              this._name = name;
              super();   //错误,构造函数中 super必须放在this之前
          }
      }
      

      调用父类方法,super作为对象:在实例方法中指向父类实例对象;在静态方法中,指向父类

      //父类
      class Person{
           //静态方法
           static getAge(){
             return 20;
           }
           //实例方法
           getName(){
             return 'zcmain';
           }
      }
      //子类
      class Man extends Person{
           constructor(){
             super();
             console.log(super.getName());  //在实例方法中,super指向父类Person实例
           }
        
           static printName(){
             console.log(super.getAge);    //静态方法中,super指向父类本身
           }
      }
      
10. ES6 模块

ES6引入了模块化。设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量

ES6模块化分为导出(export)和导入(import

特点

  • ES6模块自动启动严格模式,不管在模块头使用加use strict;
  • 导入和导出支持:变量对象字符串数字布尔等;
  • 每个模块都有自己的上下文,每个模块内声明的变量都是局部变量,不会污染作用域;
  • 每个模块只加载一次(单例),若再去加载同目录下文件,直接从缓存中读取;

注意

  • Node.js暂不支持export和import可用es-checker命令查看node支持ES6情况;
  • 目前浏览器支持ES6情况有限,在支持的浏览器中需要指定type=“module”,import的时候必须带上.js的后缀名。

基本用法

  • 说明

    • 导出(export)的函数声明、类声明必须要有名称(export default命令另外考虑)
    • 不仅能导出声明,还能导出引用(例如函数)
    • export命令可以出现在模块的任何位置,但必须出现在模块顶层(即导出模块必须在{}内)
    • import命令会提升到整个模块的头部,首先执行.
  • 导出(export)

    Test1.js

    /**
     *批量导出
     */
    let name = 'zcmain';               //字符串变量
    let age = 20;                      //数值变量
    let isLogin = false;               //布尔变量
    export let Obj = {name:'zcmain'};  //对象
    let userClass = class User{static name = 'zcmain';};  //类
    let fun = function(){console.log('this is fuction')}  //函数
    export {name,age,isLogin,Obj,userClass,fun}
    
    /**
     *逐个导出
     */
    export let name = 'zcmain';           //字符串变量
    export let age = 20;                  //数值变量
    export let isLogin = false;           //布尔变量
    export let Obj = {name:'zcmain'};     //对象
    export let userClass = class User{static name = 'zcmain';};  //类
    export let fun = function(){console.log('this is fuction')}  //函数
    
  • 导入(import)

    • 使用

      import {name,age,isLogin,Obj,userClass,fun} from './test.js'
      console.log(name);      	   //zcmain
      console.log(age);       		 //20
      console.log(isLogin);  	 		 //false
      console.log(Obj.name); 			 //zcmain
      console.log(userClass.name); //zcmian
      console.log(fun());					 //this is fuction
      
    • 特点

      1. 只读属性(不能改写加载导入模块脚本内引用指向):

        不可改导入接口的引用指向变量类型为基本类型值

        可改变量类型为对象类型属性值

        //导出基本类型age
        export age = 20;
        
        //导出对象类型Obj
        export let Obj = {
          age:20,
        }
        
        
        //导入对象类型Obj模块,和基本类型name
        import {Obj,name} from 'xxx';
        Obj = {};       //error,不可改写导出接口的引用指向
        name = 26;      //error ,不可改写导出类型为基本类型的值
        Obj.age = 26;   //Obj = {age:26}
        
      2. 多次重复执行同一句import语句,只会执行一次;import同一个模块不同接口变量,但只执行一次

        //import重复执行同一句
        import { a } "./xxx.js";
        import { a } "./xxx.js";
        // 相当于 import { a } "./xxx.js";
        
        
        //import同一个模块不同接口变量
        import { a } from "./xxx.js";
        import { b } from "./xxx.js";
        // 相当于 import { a, b } from "./xxx.js";
        
  • 使用as重新定义导入/导出接口名,隐藏模块内部变量

    1. 重命名导出接口
    let name = 'zcmain';
    //将变量name重新命名为Name导出
    export{Name as name}  
    
    //导入
    import {Name} from 'xxx';
    
    1. 重命名导入接口
    let name = 'zcmain';
    export {name}
    //导将入的变量name重命名为Name
    import {Name as name} from 'xxx';
    
  • export default命令

    • 同一个文件模块中,只能出现一次export default; 但是export可以有多个;

    • 通过export导出,在导入时需要加**{}; 而export default**则不需要;

    • export default向外导出的成员,可以使用任意变量来接收

      let a = "My name is Tom!";
      export default a;               // 仅有一个export default
      export default var c = "error"; // error,default 已经是对应的导出变量,不能跟着变量声明语句
      
      //导入
      import b from "./xxx.js";       // 不需要加{}, 使用任意变量接收
      
  • 组合使用 export & export default

    //将 person 转换为 default
    export {person as default} from 'xxx';
    
    //将default转成 person
    export {default as person} from 'xxx';
    
    //导入Test.js接口中多有导出的模块
    export * from 'Test.js';   
    
11. ES6 Promise对象

Promise是一个对象,从它可以获取异步操作的消息。

1. Promise状态

  • 特点

    1. Promise异步操作只有三个状态:pending(进行中)fulfilled(已完成)rejected(已失败)

    2. Promise状改变只能是:padding—>fulfilledpending—>rejected的状态改变,只要处于fulfilledrejected,状态就不会再变了,已定型。

    const p1 = new Promise(function(resolve,reject){
          resolve('success1');    //状态已完成回调,后续resolve状态不会再变更
          resolve('success2');
    });
    p1.then(function(value){
      		console.log(value);    //success1
    })const p2 = new Promise(function(resolve,reject){
          resolve('success3');   //状态已完成回调,后续reject状态不再改变
          reject('reject');
    });
    p2.then(function(value){
          console.log(value);   //success3
    });
    
  • 缺点

    1. Promise无法取消,一旦新建立即执行,无法中途取消。
    2. 如果不设置回调函数,Promise内部抛出错误,不会反应到外部。
    3. 当处于pending状态时候,无法得知目前进展到哪个阶段(刚刚开始,还是即将完成)

2. then方法

  • 参数

    为两个函数,两个函数只有一个会被调用

    • 第一个参数为:Promise执行成功fulfilled时回调
    • 第二个参数为:Promise执行失败rejected时回调,rejected必须被处理,否则整个会catch

    Promise执行成功,then只会回调fulfilled

    const p1 = new Promise((resolve,reject)=>{
           resolve('success');
    });
    p1.then((value)=>{
      console.log(value);       //success
    },(reason)=>{
      console.log(reason);      //不会执行,失败回调
    });
    

    Promise执行失败,then只会回调rejected

    const p2 = new Promise((resolve,reject)=>{
         reject('rejected...');
    });
    p2.then((value)=>{
      console.log(value);      //不会执行,成功回调
    },(reason)=>{
         console.log(reason);  //rejected...
    });
    

    Promise执行失败,then不处理失败回调会导致异常

    const p3 = new Promise((resolve,reject)=>{
          reject('rejected...');
    });
    //由于p3的then方法没有对失败rejected处理,导致异常,
    p3.then((value)=>{
      	console.log(value);
    });
    
    //可通过catch方法捕获异常
    p3.then((value)=>{
      	console.log(value);
    }).catch((reason)=>{
      	console.log(reason);    //使用catch对异常进行捕获
    });
    
  • then方法特点

    1. 在JavaScript事件(非延迟)队列运行完成之后才会调用回调函。

      const p1 = new Promise((resolve,reject)=>{
            resolve('success');
      });
      
      p1.then((value)=>{
         console.log(value);
      });
      
      console.log('a');
      console.log('b');
      setTimeout(()=>{
              console.log('c');
      },1000);
      
      //打印结果
      
      //a
      //b
      //success
      //c
      
    2. .then方法返回一个fulfilledrejected状态的Promise对象用于链式调用

      new Promise((relove,reject)=>{
             resolve(10);
      }).then((value)=>{
        console.log(value);   //10
        //将结果处理后返回到下一个then方法中
        return value*2;
      }).then((value)=>{
        console.log(value);   //20
        //没有返回处理
      }).then((value)=>{
        console.log(value);   //undefined 上一层没有返回,因此此处是undefined
        //返回失败
        return Promise.reject('rejected');
      }).then((value)=>{
         console.log(value);  //不会回调,上一层返回执行失败,走rejcted失败回调
      },(reason)=>{
         console.log(reason); //rejected
      });
      
  • 注意

    大多数浏览器中不能终止的 Promise 链里的 rejection,建议后面都跟上 .catch(error => console.log(error));

12. ES6 async函数

ES6async函数是ES7才有的与异步操作有关的关键字,和PromiseGenerator有很大的关联

  • 语法

    async function name(params){ statements }
    
    • name:函数名称
    • params:要传递给哈书的参数名称
    • statements:函数体语句
  • 返回值

    async函数返回一个Promise对象,可使用then方法添加回调函数

    async function add(a,b){
      return a+b;
    }
    add(1,2).then((value)=>{
      console.log(value);  //3
    });
    
  • await表达式

    1. await 操作符用于等待一个Promise对象,它只能在异步函数async函数内部使用。

    2. 正常情况下,await命令后面跟一个Promise对象,也可跟其他值:字符串、布尔值、数值、普通函数

    3. await 针对所跟不同表达式的处理方法

      • Promise对象:await会暂停执行,等待Promise对象resolve,然后恢复async函数的执行并返回解析值
      • 非Promise对象:直接返回对应值
      //Promise对象
      let promise = new Promise((resolve) => {
           setTimeout(() => {
               console.log('promise...');
               resolve();
           }, 1000);
       });
      
      //普通函数(内部有延迟)
      function fun1() {
          setTimeOut(()=>{
             console.log('普通函数..');
          },1000);
      }
      //字符串
      const str = 'zcmain';
      //布尔
      const bool = false;
      
      
      //声明async函数
      async function fun(){
        /**
         *await 命令后面跟Promise对象,暂停执行后续业务,等待Promise返回resolve,然后恢复async函数
         *执行后续业务
         */
        await promise;
        
        //await 命令后跟普通函数,不暂停,继续执行后续业务(即使时内部有延迟任务)
        await fun1();  
        
        //await 命令后跟字符串,直接返回
        let str = await 'zcmain'; 
        
        //await 命令后跟布尔值,直接返回
        let bool = await false;		  
      }
      fun();
      //promise...
      //zcmain
      //false
      //普通函数...          //await 后面跟普通内部有延迟任务函数,并没有暂停,先执行了字符串和布尔值
      
=============================
11. 数据类型

ES6数据类型除了:NumberString Boolean Object null undefined还新增了Symbol

  • Symbol

    Symbol表示独一无二的值,最大的用法是用来定义对象的唯一属性名!

12. Proxy 与 Reflect

Proxy与Reflect是ES6为操作对象而引入的API

Proxy:通过对象的代理对目标对象的读取、函数调用等操作进行拦截,比如添加一些需要额外的操作。

Reflect:用于获取目标对象的行为,它的方法与Proxy是对应的。

13. ES6 Generator函数

ES6引入Generator函数,可以通过yield关键字,把函数的执行流程挂起,为改变执行流程提供可能,从而为异步编程提供解决方案。

  • Generator函数组成

    Generator函数区分于普通函数部分:

    1. 在function后面,函数名之前有*****标识符
    2. 函数内部有yiled表达式

    其中***用来表示函数为Generator函数,yiled**用来定义函数内部状态

    //声明Generator函数(函数名前有 * 标识符,内部有yiled关键字)
    function *fun(){
      console.log('one');
      yiled '1';
      console.log('two');
      yiled '2';
      console.log('three');
      return '3';
    }
    
  • 执行机制

    调用Generator函数和调用普通函数一样,函数名后面加上**()**即可,但是Generator函数不会像普通函数一样立即执行,而是返回一个指向内部状态的指针,因此要调用遍历对象的Iterator的next方法,指针就会从函数头部或上一次停下来的地方开始执行

    fun.next();   //one 
    

扩展

1. JS中this指向

在js中this对象是在运行时基于函数的执行环境绑定的:

  • 函数没有直接的挂载者(或称调用者),函数中this是指向window;

  • 函数作为某个对象方法被调用时候,则this指向当前调用对象;

  • 匿名函数(setTimeOut、setInterval)的执行环境是全局的则this指向全局window;

1.1 单独函数调用

函数没有直接的挂载者(或调用者),函数中this 指向 window

function fn(){
    console.log(this);
    function fn2(){
      console.log(this);
      function fn3(){
        console.log(this);
      }
      fn3();   //fn3() 独立函数调用,不借助对象,this指向全局window
    }
  fn2();       //fn2() 独立函数调用,不借助对象,this指向全局window
}
fn();          //fn()  独立函数调用,不借助对象,this指向全局window

1.2 对象调用

函数作为某个对象的方法被调用时this指向调用对象,即调用宿主

let Obj = {
    age:20,
    fn:function(){
      console.log(this);
      console.log(this.age); //20
      function fn1(){
        console.log(this);
      }
      fn1();  //fn1()  独立函数调用,不借助对象,this指向全局window
    } 
}
//对象调用 fn函数借助Obj对象调用,this指向调用的对象Obj,因此内部this.name可访问Obj中的属性
Obj.fn();  

箭头函数this指向

箭头函数的this是在定义函数时绑定的,不是在执行过程中绑定的。

简单的说:箭头函数在定义时,this就继承了定义函数的对象

  • 适合使用的场景

    ES6 之前,JavaScript 的 this 对象一直很令人头大,回调函数,经常看到 var self = this 这样的代码,为了将外部 this 传递到回调函数中,那么有了箭头函数,就不需要这样做了,直接使用 this 就行。

    所以,当我们需要维护一个 this 上下文的时候,就可以使用箭头函数。

    案例:如何通过回调函数访问对象的属性?

    //全局age
    let age =20;     
    let Person = {
      age:18,
      getAge:function(){
        setTimeOut(function(){    
          console.log(this.age);  //匿名函数内部this指向的是全局window
        })}
    }
    Person.getAge(); // 20 this.age指向的是全局的age,并非Person对象中的age
    
    1. 使用let that = this实现回调函数访问对象中属性
    //全局age
    let age = 20;
    let Person = {
      age:18,
      getAge:function(){
        let that = this;     //在getAge函数内部将当前this赋值给that变量,该this是指向Person对象的
        setTimeOut(function(){
          console.log(that.age);  //回调匿名函数中通过使用that来访问Person属性
        },0)
      }
    }
    Perosn.getAge();  //18
    
    1. 使用箭头函数实现回调函数访问对象中属性
    //全局age
    let age = 20;
    let Person = {
      age:18,
      getAge:function(){
        setTimeOut(()=>{
          console.log(this.age);  //箭头函数中this指向定义的函数的对象Person
        },0)
      }
    }
    Perosn.getAge();  //18
    
  • 不适合使用场景

    箭头函数不适用于定义函数的方法,且该方法中包含this

    let Obj1 = {
        name: 'obj1',
        fun1: () => {
            //使用箭头函数定义函数方法,此时 this 指向外层对象即全局对象window。
            console.log('fun1', this);
        },
        fun2: function () {
            //使用传统function定义函数方法,此时this指向Obj1对象。
            console.log('fun2', this);
            let Obj2 = {
                name: 'obj2',
                fun3: function () {
                    //使用传统function定义函数方法,此时this指向Obj2
                    console.log('fun3', this);
                },
                fun4: () => {
                    //使用箭头函数定义函数方法,此时this指向外层对象,即fun2函数中this对象Obj1。
                    console.log('fun4', this);
                },
            };
            Obj2.fun3();
            Obj2.fun4();
        },
    };
    Obj1.fun1();
    Obj1.fun2();
    

在这里插入图片描述

2. 解释执行和编译执行语言的优缺点

计算机只能执行低级语言中的指令(机器语言)(汇编语言的指令需要先转换成机器码才能执行),对于我们的使用高级语言开发出来的程序,想要计算机执行,必须要将高级语言翻译成低级语言!

高级语言翻译为低级语言的方法有两种:

  • 解释:在程序运行时候将高级语言翻译成机器语言。
  • 编译:在程序执行之前有个单独的编译过程,将程序翻译成机器语言,执行时候就不需要再进行翻译了。

从可执行效率来说**解释执行编译执行**各自优缺点:

  • 解释执行

    • 优点
      1.不依赖平台
      2.开发速度快
    • 缺点
      1.执行速度低(运行时需要一句一句翻译,速度慢)
      2. 浪费内存和CPU(执行过程中需要一句一句的翻译消耗内存)
      3. 源码必须交给用户

    Java C# JS 等都是解释型语言,虽然java程序要有个编译过程,但并不是将程序编译成机器语言,而是键它编译成字节码(可理解为一个中间语言),在运行时候,由JVM将字节码再翻译成机器语言。

  • 编译执行

    • 优点
      1.执行速度快(编译后的机器语言直接执行,用C/C++编写的程序运行速度要比java编写的相同程序快30%~70%)
      2.消耗内存小
    • 缺点
      1.兼容性差(编译是面向特定平台,因此是平台依赖的)
      2.安全性低(一个编译型程序可以访问内存任何区域,大部分病毒使用编译型语言开发)
      3.开发难度高

    C C++都是编译型语言

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值