变量提高的概念 :深刻理解 js 变量提高html
闭包 :闭包,是真的美前端
谈到闭包拉扯到垃圾回收机制 阮一峰JavaScript 内存泄漏教程java
函数式高级编程==》柯里化函数与组合函数node
柯里化函数:「前端进阶」完全弄懂函数柯里化git
组合函数:「前端进阶」完全弄懂函数组合es6
JS引擎会在正式执行以前先进行一次预编译,在这个过程当中,首先将变量声明及函数声明提高至当前做用域的顶端,而后进行接下来的处理。github
变量提高面试
function hoistVariable() {
var foo = foo || 5;
console.log(foo); // 5
}
---》预编译以后
function hoistVariable() {
var foo;
foo = foo || 5;
console.log(foo); // 5
}
复制代码
函数提高算法
function hoistFunction() {
foo(); // output: I am hoisted
function foo() {
console.log('I am hoisted');
}
}
复制代码
------》编译以后编程
function hoistFunction() {
function foo() {
console.log('I am hoisted');
}
foo(); // output: I am hoisted
}
复制代码
闭包就是可以读取其余函数内部变量的函数,【在本质上,闭包是将函数内部和函数外部链接起来的桥梁】
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
复制代码
闭包的用途 什么是闭包?闭包的做用,用法及优缺点
能够读取函数内部的变量
让这些变量的值始终保持在内存中
function f1(){
    nAdd=function(){n+=1} //nAdd是全局函数
  }
复制代码
使用闭包的注意点
(1)因为闭包会使得函数中的变量都被保存在内存中,内存消耗很大,因此不能滥用闭包,不然会形成网页的性能问题,在IE中可能致使内存泄露。解决方法是,在退出函数以前,将不使用的局部变量所有删除
function foo() {
let a = 2;
function bar() {
console.log( a );
}
return bar;
}
let baz = foo();
baz(); //baz指向的对象会永远存在堆内存中
baz = null; //若是baz再也不使用,将其指向的对象释放
复制代码
垃圾回收机制怎么知道,哪些内存再也不须要呢?:
最常使用的方法叫作"引用计数"(reference counting):语言引擎有一张"引用表",保存了内存里面全部的资源(一般是各类值)的引用次数。若是一个值的引用次数是0,就表示这个值再也不用到了,所以能够将这块内存释放
const arr = [1, 2, 3, 4];
console.log('hello world');
复制代码
上面代码中,数组[1, 2, 3, 4]是一个值,会占用内存。变量arr是仅有的对这个值的引用,所以引用次数为1。尽管后面的代码没有用到arr,它仍是会持续占用内存。
若是增长一行代码,解除arr对[1, 2, 3, 4]引用,这块内存就能够被垃圾回收机制释放了
let arr = [1, 2, 3, 4];
console.log('hello world');
arr = null;
复制代码
柯里化,能够理解为提早接收部分参数,延迟执行,不当即输出结果,而是返回一个接受剩余参数的函数。由于这样的特性,也被称为部分计算函数。柯里化,是一个逐步接收参数的过程。在接下来的剖析中,你会深入体会到这一点。
一道经典面试题multi(2)(3)(4)=24?
实现 multi 函数去计算出结果值呢?脑海中首先浮现的解决方案是,闭包
function multi(a) {
return function(b) {
return function(c) {
return a * b * c;
}
}
}
复制代码
实现方案存在的缺陷
使用函数柯里化 解决
//实现乘积功能,返回得是函数
function multi() {
var args = Array.prototype.slice.call(arguments);//获取到实参借用数组的slice方法
var fn = function() { //解决多个括号的问题//multi(2,3,4,5)(1,2,7,5)
var newArgs = args.concat(Array.prototype.slice.call(arguments));//获取数组
return multi.apply(this, newArgs);//调用下面的方法
}
//返回的结果转字符串,每一次会先执行这个核心方法
fn.toString = function() { //multi(2,3,4,5)
//数组reduce方法相称
return args.reduce(function(a, b) {
return a * b;
})
}
return fn;//多个括号调用第一个方法fn,否者直接返回
}
复制代码
柯里化使用场景 简述几个很是有用的柯里化函数使用场景 /// JS专题之函数柯里化
----》先不顾忌反柯里化,讲到柯里化,能够在牵扯到另外一个高级编程函数compose组合函数 JavaScript高级编程
compose组合函数 JavaScript专题之函数组合 /// 组合 (compose) /// JS 函数式编程指南
最多见的继承方法就是使用原型链实现继承
//父类
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
}
//子类
function SubType() {
ths.subproperty = true;
}
//继承
SubType.prototype = new SuperType();// 实现继承
SubType.prototype.getSubValue = function() {
return this.subprototype;
}
//实例化
var instance = new SubType();
console.log(instance.getSuperValue());// true
复制代码
继承原理 子类SubType默认提供的原型===》它换了一个新原型(即父类SuperType的实例)===》子类SubType具备父类SuperType实例所拥有的所有实现和方法(指向父类SuperType的原型)=======》instance实例具备父类SuperType的subproperty属性
经过原型链寻找原理 调用实例以后的instance的getSuperValue() ===》instance实例上找不到该方法(即子类SubType)====》 顺着原型链先找到SubType.prototype===》顺着原型链找到SuperType.prototype。
若是该属性为引用类型时,全部的实例都会共享该属性,一个实例修改了该属性,其它实例也会发生变化,同时,在建立子类型时,咱们也不能向超类型的构造函数中传递参数
(由原型继承延申至此)为了解决原型中包含引用类型值所带来的问题,开发人员开始使用借用构造函数的技术实现继承,该方法主要是经过apply()和call()方法,在子类型构造函数的内部调用超类型构造函数,从而解决该问题。
function SuperType(name,colors) {
this.name=name;
this.colors = ["red","blue","green"]
}
function SubType(name,colors) {
SuperType.call(this,name,colors);// 实现继承
this.age = 29;
this.name = "Nasx";
}
var instance1 = new SubType();
var instance2 = new SubType();
instance2.colors.push("black");
console.log(instance1.colors);// red,blue,green
console.log(instance2.colors);// red,blue,green,black
console.log(instance2.name);//
复制代码
经过使用call()方法,咱们其实是在新建立的SubType实例的环境下调用了SuperType的构造函数,所以,colors属性是分别存在instance1和instance2实例中的,修改其中一个不会影响另外一个。
call和apply的区别:用来改变this的指向的
传参列表:第一位传的都是改变this指向的那个,第二位call能够一位一位的传实参列表进去,可是,apply只能传一位,并且必须是数组形式的实参。
call须要把实参按照形参的个数传进去,
apply须要传一个arguments
bind() //返回的是方法,bind的时候传的参数会预先传给返回的方法,调用方法时就不用再传参数了。
function Car(wheelSize,style,c,sitColor,height,width,len){
Wheel.apply(this,[wheelSize,style]);
Sit.apply(this,[c,sitColor]);
Model.apply(this,[height,width,len]);
}
复制代码
优势:解决了原型链继承中引用类型的共享问题,同时能够在子类型构造函数中向超类型构造函数传递参数。
缺点:定义方法时,将会在每一个实例上都会从新定义,不能实现函数的复用。
组合继承主要是将原型链和借用构造函数的技术组合到一块
原型链--->实现对原型属性和方法的基础
借用构造函数--->实现对实例属性的基础
//先经过借用构造函数call实现实例属性的基础
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"]
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name,age) {
SuperType.call(this,name);
this.age = age;
}
//借用原型链实现对原型的属性和方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
console.log(this.age);
}
复制代码
这边先解决原型链/原型
var person = {
name: "Nicholas",
friends: ["Shelby","Court","Van"]
}
var anotherPerson = Object.create(person, {
name: {
value: "Greg"
}
});
console.log(anotherPerson.name); // Greg
复制代码
让anotherPerson继承了person,其中,friends做为引用类型,将会被全部继承该对象的对象所共享,而经过传入第二个参数,咱们能够定义额外的属性,修改person中的原有信息。
建立一个仅用于封装继承过程的函数,该函数在内部以某种方法来加强对象,最后再返回该对象。
function createAnother(original) {
var clone = Object(original);
// 经过调用函数建立一个新对象
clone.sayHi = function() {
console.log("hi");
}
return clone;
}
复制代码
看作是传进去一个对象,而后对该对象进行必定的加工,也就是增长一些方法来加强该对象,而后再返回一个包含新方法的对象的一个过程
var person = {
name: "Nicholas",
friends:["Shelby","Court","Van"]
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); // hi
复制代码
person是没有包含任何方法的,而经过将person传进去createAnother方法中进行加工,返回的新对象就包含了一个新的方法
组合继承是js中最常常用到的一种继承方法,而咱们前面也已经说了组合继承的缺点,组合继承须要调用两次超类型构造函数,一次是在建立子类型原型的时候,另外一次是在子类型构造函数内部,子类型最终会包含超类型对象的所有实例属性,可是咱们不得不在调用子类型构造函数时重写这些属性。
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"]
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name,age) {
SuperType.call(this,name); // 第二次调用超类型构造函数
this.age = age;
}
SubType.prototype = new SuperType(); // 第一次调用超类型构造函数
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
console.log(this.age);
}
复制代码
结果就是在SubType.prototype和SubType的实例上都会建立name和colors属性,最后SubType的实例上的name和colors属性会屏蔽掉SubType.prototype上的name和colors属性
寄生组合式继承主要经过借用构造函数来继承属性,经过原型链的混成形式来继承方法,其实就是没必要为了指定子类型的原型而调用超类型的构造函数,只须要超类型原型的一个副本就能够了。
function inheritPrototype(subType,SuperType) {
var prototype = Object(SuperType); // 建立对象
prototype.constructor = subType; // 加强对象
subType.prototype = prototype; // 指定对象
}
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"]
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name,age) {
SuperType.call(this,name);
this.age = age;
}
//避免了在SubType.prototype上面建立的没必要要的,多余的属性
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function() {
console.log(this.age);
}
复制代码
es6中可使用Class来建立对象,而一样的道理,在es6中,也新增长了extends实现Class的继承,Class 能够经过extends关键字实现继承,这比 ES5 的经过修改原型链实现继承,要清晰和方便不少
class Point {}
class ColorPoint extends Point {}
复制代码
上面这个例子中能够实现ColorPoint类继承Point类,这种简洁的语法确实比咱们上面介绍的那些方法要简洁的好多呀。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
this.color = color; // ReferenceError
super(x, y);
this.color = color; // 正确
}
}
复制代码
后面还会讲到类比继承
解决全部异步的方式
异步 撸js基础之异步
加深执行顺序的理解 从一道Promise执行顺序的题目看Promise实现
手写题(能够不会,可是须要大概理解思路以及大意)「中高级前端面试」JavaScript手写代码无敌秘籍
看这个就行了 RESTful 架构风格概述
let arr=[1,2,3,4,5];
//forEach s数组遍历 可传值
arr.forEach(function(value,index){
console.log(value);
console.log(index)
})
复制代码
let arr1=arr.map(function(value){
return value*2+1
} )
复制代码
let arr2=arr.filter(function(value){
return value>2
})
console.log(arr2)
复制代码
let arr3=arr.some(function(value){
return value>5
})
复制代码
let arr4=arr.every(function(value){
return value>0
})
console.log(arr4)//true
复制代码
console.log(arr.indexOf(5));
if(arr.indexOf(5)>1){
console.log("正确")
}
复制代码
let arr=[1,2,3,4,5];
let result=arr.reduce(function(last,now){
return last+now;
},0)//后边跟开始跟那个计算
console.log(result)//15
复制代码
(Number的属性不用强调)=》检测有穷数/检测整数/转化浮点数/转化整数/转化字符串/返回对象原始值
方法用来检测传入的参数是不是一个有穷数
ps:返回布尔类型:
Number.isFinite(NaN) //false
Number.isFinite(Infinity); // false
复制代码
(全局的 isFinite(),会强制转化类型)不会强制将一个非数值的参数转换成数值,这就意味着,只有数值类型的值,且是有穷的(finite),才返回 true
方法用来判断给定的参数是否为整数
ps:返回布尔类型
Number.isInteger("10"); // false
Number.isInteger(-100000); // true
复制代码
注意 NaN 和正负 Infinity 不是整数。
Number.isSafeInteger():表示给定的值是不是一个安全整数(safe integer)。很少用
Number.parseFloat(string):被解析的字符串
ps:一个字符串解析成浮点数。该方法与全局的 parseFloat() 函数相同,对(**首字符不可为非数值**)字母**会进行隐式转化删除**
Number.parseFloat("sss") //NaN
Number.parseFloat(true) //NaN
复制代码
给定值被解析成浮点数,若是没法被解析成浮点数,则返回NaN
方法依据指定基数 [ 参数 radix 的值],把字符串 [ 参数 string 的值] 解析成整数。(指定转化什么进制的)
ps:一个字符串能够解析指定的多少进制,对(首字符不可为非数值)字母会进行隐式转化删除
Number.parseInt('0110', 2) //6
Number.parseInt('0110', 10) //110
Number.parseInt('1000s') //1000
Number.parseInt('d1d0d00s') //NaN
复制代码
reaix无关紧要,radix为指定基数(即字符串以多少进制的数字表示),默认十进制
返回指定 Number 对象的字符串表示形式
ps:---radix指定返回多少进制
(18).toString() //"18"
18.toString() //Invalid or unexpected token
(6).toString(2) // '110'
复制代码
Number 对象覆盖了 Object 对象上的 toString() 方法,它不是继承的 Object.prototype.toString()。对于 Number 对象,toString() 方法以指定的基数返回该对象的字符串表示。
进行数字到字符串的转换时,建议用小括号将要转换的目标括起来,防止出错。
返回一个被 Number 对象包装的原始值。
ps:该方法一般是由 JavaScript 引擎在内部隐式调用的,而不是由用户在代码中显式调用的。
var numObj = new Number(10);
console.log(typeof numObj); // object
var num = numObj.valueOf();
console.log(num); // 10
console.log(typeof num); // number
复制代码
细讲重要的属性和方法 ---------- 获取函数名称/长度/调用函数caller/apply数组/call 列表/bind 函数
返回调用指定函数的函数(函数A使用Function.caller,函数B调用函数A【Function.caller返回函数B】) 掘金
ps : arguments.callee.caller替代了被废弃的 arguments.caller 【callee返回正在执行的函数对象】
function myFunc() {
if (myFunc.caller == null) {
return ("该函数在全局做用域内被调用!");
} else
return ("调用个人是函数是" + myFunc.caller);
}
function ss(){
console.log(myFunc())
}
ss() // 调用个人是函数是function ss(){console.log(myFunc())}
复制代码
若是一个函数f是在全局做用域内被调用的,则f.caller为null,相反,若是一个函数是在另一个函数做用域内被调用的,则f.caller指向调用它的那个函数
属性指明函数的形参个数
ps:length 是函数对象的一个属性值,指该函数有多少个必需要传入的参数,即形参的个数
console.log((function(a, b) {}).length); /* 2 etc. */
console.log((function(...args) {}).length) // 0, 其余参数不计算在内
console.log((function(a, b = 1, c) {}).length);
// 1, b=1是计算,阻断了计算
// 只有一个a
复制代码
【arguments.length 是函数被调用时实际传参的个数】,Function.prototype 对象的 length 属性值为 0
函数声明的名称:(直接返回名称)
function doSomething() { }
doSomething.name; // "doSomething"
复制代码
构造函数的名称 :变量和方法能够从句法位置推断匿名函数的名称
ps:不能经过此方法赋值更改函数的名称,此属性是只读的,要更改它,可使用Object.defineProperty()
var f = function() {};
var object = {
someMethod: function() {}
someMethods: function object_someMethod() {}
};
console.log(f.name); // "f"
console.log(object.someMethod.name); // "someMethod"
console.log(object.someMethods.name); // "object_someMethod"
复制代码
简写方法的名称
var o = {
foo(){}
};
o.foo.name; // "foo";
复制代码
绑定函数的名称 : Function.bind() 所建立的函数将会在函数的名称前加上"bound " 。
function foo() {};
foo.bind({}).name; // "bound foo"
复制代码
【数组】调用一个具备给定this值的函数,以及做为一个数组(或相似数组对象)提供的参数。
ps:call()方法的做用和 apply() 方法相似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。
var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers);
console.log(max);
// expected output: 7
复制代码
语法:function.apply( thisArg , [ argsArray ] )
thisArg: 可选的。在 func 函数运行时使用的** this** 值来改变this指向
argsArray:可选的。一个数组或者类数组对象,其中的数组元素将做为单独的参数传给 func 函数。若是该参数的值为null 或 undefined,则表示不须要传入任何参数
调用有指定this值和参数的函数的结果。
用 apply 将数组添加到另外一个数组(concat确实具备咱们想要的行为,但它实际上并不附加到现有数组,而是建立并返回一个新数组)
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
复制代码
方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数
-------------------------------------------------使用 call 方法调用父构造函数
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
//调用父构造函数
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
复制代码
-------------------------------------------------使用 call 方法调用匿名函数
var animals = [
{ species: 'Lion', name: 'King' },
{ species: 'Whale', name: 'Fail' }
];
for (var i = 0; i < animals.length; i++) {
(function(i) {
this.print = function() {
console.log('#' + i + ' ' + this.species
+ ': ' + this.name);
}
this.print();
}).call(animals[i], i);
}
复制代码
-------------------------------------------------使用 call 方法调用函数而且指定上下文的 'this'
function greet() {
var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
console.log(reply);
}
var obj = {
animal: 'cats', sleepDuration: '12 and 16 hours'
};
greet.call(obj); // cats typically sleep between 12 and 16 hours
复制代码
建立一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其他的参数将做为新函数的参数供调用时使用
-----------------------------------------------------例子
var module = {
x: 42,
getX: function() {
return this.x;
}
}
var unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
复制代码
---------------------------------------------------实现bind
//判断浏览器是否function内置bind方法
if(!Function.prototype.bind){
Function.prototype.bind = function(oThis) {
if(typeof this !== 'function'){
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable')
}
//获取参数,从1开始(为啥呢,由于bind方法有个this指向问题)
var args=Array.prototype.slice.call(arguments,1),
fToBind = this, //指向的是绑定的函数
fNOP=function(){},//定义空函数(由于返回的是一个函数)
fBound=function(){
// this instanceof fBound === true时,说明返回的fBound被当作new的构造函数调用
return fToBind.apply(this instanceof fBound?this:oThis,Args.concat(Array.prototype.slice.call(arguments))) //借用方法
}
// 维护原型关系(this指向不是window)
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,所以
// 返回的fBound若做为new的构造函数,new生成的新对象做为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
}
}
复制代码
方法返回一个表示当前函数源代码的字符串。
几乎全部的 JavaScript 对象都是 Object 的实例;一个典型的对象继承了Object.prototype的属性(包括方法)
返回建立实例对象的 Object 构造函数的引用。注意,此属性的值是对函数自己的引用,而不是一个包含函数名称的字符串
//实例对象是Object
var o = {};
o.constructor === Object; // true
var o = new Object;
o.constructor === Object; // true
复制代码
方法用于将全部可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
用法
复制一个对象
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
复制代码
深拷贝问题:深拷贝属性值(对象里的属性),浅拷贝对象(对象里的对象)
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
复制代码
合并对象
const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };
const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。
复制代码
合并具备相同属性的对象
const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };
const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
复制代码
原始类型会被包装为对象
const v1 = "abc";
const v2 = true;
const v3 = 10;
const v4 = Symbol("foo")
const obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 原始类型会被包装,null 和 undefined 会被忽略。
// 注意,只有字符串的包装对象才可能有自身可枚举属性。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
复制代码
异常会打断后续拷贝任务
建立一个新对象,使用现有的对象来提供新建立的对象的__proto__((指定_proto_)可用来指定原型)
语法:Object.create(proto[, propertiesObject])
------------继承之原型式继承
var person={
name:"Nicho",
friends:["Shelby","Count","Van"]
}
var anthor=Object.create(person,{
name:{
value:"Geral"
}
})
console.log(anthor.name) //Geral
复制代码
----------------继承之类比继承
// Shape - 父类(superclass)
function Shape() {
this.x = 0;
this.y = 0;
}
// 父类的方法
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - 子类(subclass)
function Rectangle() {
Shape.call(this); // call super constructor.
}
// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
复制代码
方法直接在一个对象上定义一个或多个新的属性或修改现有属性,并返回该对象 学习
语法: Object.defineProperties(obj, props)
obj: 将要被添加属性或修改属性的对象
props: 该对象的一个或多个键值对定义了将要为对象添加或修改的属性的具体配置
var obj = {};
Object.defineProperties(obj, {//数据描述符
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
});
复制代码
数据(数据述符)属性
configurable:为false,则不可以使用delete操做符(在严格模式下抛出错误), 修改全部内部属性值会抛出错误,在《javaScript高级教程中》说只能够改变writable的值,如今改变writable的值也会抛出错误,默认为 false。
Enumerable:该属性是否可枚举,便是否经过for-in或Object.keys()返回属性,若是直接使用字面量定义对象,默认为 false
value:与属性关联的值。能够是任何有效的JavaScript值(数字,对象,函数等),默认为 undefined.
writable:当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为 false。
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
若是不指定configurable, writable, enumerable ,则这些属性默认值为false,若是不指定value, get, set,则这些属性默认值为undefined
语法:Object.defineProperty(obj, prop, descriptor)
obj: 须要被操做的目标对象
prop: 目标对象须要定义或修改的属性的名称
descriptor: 将被定义或修改的属性的述符
var o = {}; // 建立一个新对象
// 在对象中添加一个属性与数据描述符的示例(数据描述符)
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true
});
// 对象o拥有了属性a,值为37
// 在对象中添加一个属性与存取描述符的示例(存取数据夫)
var bValue;
Object.defineProperty(o, "b", {
get : function(){ //获取操做
return bValue;
},
set : function(newValue){ //拦截操做
bValue = newValue;
},
enumerable : true,
configurable : true
});
o.b = 38; // newValue为38 o.b也是38
复制代码
存取描述符属性
configurable:为false,则不可以使用delete操做符(在严格模式下抛出错误), 修改全部内部属性值会抛出错误,在《javaScript高级教程中》说只能够改变writable的值,如今改变writable的值也会抛出错误,默认为 false。
Enumerable:该属性是否可枚举,便是否经过for-in或Object.keys()返回属性,若是直接使用字面量定义对象,默认为 false
get:一个给属性提供 getter 的方法,若是没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,可是会传入this对象(因为继承关系,这里的this并不必定是定义该属性的对象)。
Set:一个给属性提供 setter 的方法(给对象属性设置值时调用的函数),若是没有 setter 则为 undefined。该方法将接受惟一参数,并将该参数的新值分配给该属性。默认为 undefined
configurable | enumerable | value | writable | get | set | |
---|---|---|---|---|---|---|
数据描述符 | Yes | Yes | Yes | Yes | No | No |
存取描述符 | Yes | Yes | No | No | Yes | Yes |
若是一个描述符不具备value,writable,get 和 set 任意一个关键字,那么它将被认为是一个数据描述符。若是一个描述符同时有(value或writable)和(get或set)关键字,将会产生一个异常。
返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环也枚举原型链中的属性)。
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
// array like object
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
// array like object with random key ordering
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]
复制代码
冻结一个对象。一个被冻结的对象不再能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。
方法接收一个键值对的列表参数,并返回一个带有这些键值对的新对象
Map 转化为 Object
const map = new Map([ ['foo', 'bar'], ['baz', 42] ]);
const obj = Object.fromEntries(map);
console.log(obj); // { foo: "bar", baz: 42 }
复制代码
Array 转化为 Object
const arr = [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ];
const obj = Object.fromEntries(arr);
console.log(obj); // { 0: "a", 1: "b", 2: "c" }
复制代码
返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不须要从原型链上进行查找的属性)
var person = {
name: '张三',
age: 18
}
var desc = Object.getOwnPropertyDescriptor(person, 'name');
console.log(desc) 结果以下
// {
// configurable: true,
// enumerable: true,
// writable: true,
// value: "张三"
// }
复制代码
所指定对象的全部自身属性的描述符,若是没有任何自身属性,则返回空对象
var person = {
name: '张三',
age: 18
}
var desc = Object.getOwnPropertyDescriptors(person);
console.log(desc)
复制代码
返回一个由指定对象的全部自身属性的属性名(包括不可枚举属性但不包括Symbol值做为名称的属性)组成的数组。
ps:返回一个数组,该数组对元素是 obj自身拥有的枚举或不可枚举属性名称字符串。 数组中枚举属性的顺序与经过 for...in 循环(或 Object.keys)迭代该对象属性时一致。数组中不可枚举属性的顺序未定义。
var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]
// 类数组对象
var obj = { 0: "a", 1: "b", 2: "c"};
console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]
复制代码
var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true
复制代码
方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 。若是对象的键-值都不可枚举,那么将返回由键组成的数组。
obj:要返回其枚举自身属性的对象。
// simple array
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']
// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']
// array like object with random key ordering
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']
复制代码
使用 hasOwnProperty 方法判断属性是否存在
o = new Object();
o.prop = 'exists';
function changeO() {
o.newprop = o.prop;
delete o.prop;
}
o.hasOwnProperty('prop'); // 返回 true
changeO();
o.hasOwnProperty('prop'); // 返回 false
复制代码
自身属性与继承属性
o = new Object();
o.prop = 'exists';
o.hasOwnProperty('prop'); // 返回 true
o.hasOwnProperty('toString'); // 返回 false 继承属性
o.hasOwnProperty('hasOwnProperty'); // 返回 false 继承属性
复制代码
toString() 返回 "[object type]"
> 能够经过 toString() 来获取每一个对象的类型。为了每一个对象都能经过 Object.prototype.toString() 来检测,须要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,传递要检查的对象做为第一个参数,称为 thisArg。
var toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
//Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
复制代码
URIError 对象用来表示以一种错误的方式使用全局URI处理函数而产生的错误。
TypeError(类型错误) 对象用来表示值的类型非预期类型时发生的错误。
SyntaxError 对象表明尝试解析语法上不合法的代码的错误
ReferenceError(引用错误) 对象表明当一个不存在的变量被引用时发生的错误。
RangeError对象标明一个错误,当一个值不在其所容许的范围或者集合中。
InternalError 对象表示出如今JavaScript引擎内部的错误。 例如: "InternalError: too much recursion"(内部错误:递归过深
EvalError eval 函数的错误.此异常再也不会被JavaScript抛出,可是EvalError对象仍然保持兼容性.
函数解码一个由encodeURI 先前建立的统一资源标识符(URI)或相似的例程。
decodeURI("https://developer.mozilla.org/ru/docs/JavaScript_%D1%88%D0%B5%D0%BB%D0%BB%D1%8B");
// "https://developer.mozilla.org/ru/docs/JavaScript_шеллы"
复制代码
方法用于解码由 encodeURIComponent 方法或者其它相似方法编码的部分统一资源标识符(URI)
decodeURIComponent("JavaScript_%D1%88%D0%B5%D0%BB%D0%BB%D1%8B");
// "JavaScript_шеллы"
复制代码
函数经过将特定字符的每一个实例替换为一个、两个、三或四转义序列来对统一资源标识符 (URI) 进行编码
是对统一资源标识符(URI)的组成部分进行编码的方法
使用var声明变量严格模式中将不经过
何使用'eval'的操做都会被禁止
eval做用域
with被禁用
caller/callee 被禁用
禁止扩展的对象添加新属性会报错
除系统内置的属性会报错
delete使用var声明的变量或挂在window上的变量报错
delete不可删除属性(isSealed或isFrozen)的对象时报错
对一个对象的只读属性进行赋值将报错
对象有重名的属性将报错
函数有重名的参数将报错
八进制表示法被禁用
arguments严格定义为参数,再也不与形参绑定
函数必须声明在顶层
ES5里新增的关键字不能当作变量标示符使用,如implements, interface, let, package, private, protected, pulic, static, yield
call/apply的第一个参数直接传入不包装为对象
call/apply的第一个参数为null/undefined时,this为null/undefined
bind的第一个参数为null/undefined时,this为null/undefined
前言:只写以为有用的
repeat方法返回一个新字符串,表示将原字符串重复n次。
'x'.repeat(3) // "xxx"
'na'.repeat(2.9) // "nana"
复制代码
若是某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
'x'.padStart(4, 'ab') // 'abax' 在x前面的
'x'.padEnd(5, 'ab') // 'xabab'
复制代码
--(若是原字符串的长度,等于或大于最大长度,则字符串补全不生效,返回原字符串。)
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
复制代码
消除字符串的空格--trim()[ES2019 对字符串实例新增了trimStart()和trimEnd()]
前言:只写以为有用的
实例方法:isFinite()--数值是否为有限 实例方法:.isInteger()--数值是否为整数
Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity。【Number.isNaN()用来检查一个值是否为NaN。】
ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为彻底保持不变。【是逐步减小全局性方法,使得语言逐步模块化。】
// ES5的写法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
// ES6的写法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
复制代码
Number.isInteger()用来判断一个数值是否为整数。
Number.isInteger(25) // true
Number.isInteger(25.1) // false
复制代码
前言:只写以为有用的
实例方法:Math.trunc--去除一个数的小数部分,返回整数部分 实例方法:Math.sign--判断一个数究竟是正数、负数、仍是零 实例方法:Math.cbrt:计算一个数的立方根
Math.trunc方法用于去除一个数的小数部分,返回整数部分。
Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
复制代码
Math.sign方法用来判断一个数究竟是正数、负数、仍是零。对于非数值,会先将其转换为数值。
参数为正数,返回+1;
参数为负数,返回-1;
参数为 0,返回0;
参数为-0,返回-0;
其余值,返回NaN。
复制代码
Math.cbrt方法用于计算一个数的立方根。 Math.cbrt('8') // 2
前言:扩展运算符...,将一个数组转为用逗号分隔的参数序列,有点for的意思。
1.数组叠加
//items变成序列加到array数组里
function push(array, ...items) {
array.push(...items);
}
复制代码
2.扩展运算符与正常的函数参数能够结合使用,很是灵活。
//“...”,数组变成参数
function add(x, y) {
return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42-----add(4,38)
复制代码
3.扩展运算符后面还能够放置表达式
const arr = [
...(x > 0 ? ['a'] : []),
'b',
];
复制代码
4.扩展运算符后面是一个空数组,则不产生任何效果
[...[], 1]
// [1]
复制代码
5.函数调用时,扩展运算符才能够放在圆括号中,不然会报错
(...[1, 2]) // Uncaught SyntaxError: Unexpected number
console.log((...[1, 2])) // Uncaught SyntaxError: Unexpected number
-----扩展运算符取代apply方法
// ES6 的写法 Math.max(...[14, 3, 77])
// 等同于 Math.max(14, 3, 77);
-------经过push函数,将一个数组添加到另外一个数组的尾部。
// ES6 的写法 let arr1 = [0, 1, 2]; let arr2 = [3, 4, 5]; arr1.push(...arr2);
扩展运算符的应用
(1) 复制数组
//a2并非a1的克隆,而是指向同一份数据的另外一个指针。修改a2,会直接致使a1的变化
[
const a1 = [1, 2];
const a2 = a1;
]
//扩展运算符提供了复制数组的简便写法【修改a2,不会直接致使a1的变化】
const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;
复制代码
(2)合并数组
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
复制代码
(3)解构赋值 tip:将扩展运算符用于数组赋值,只能放在参数的最后一位,不然会报错
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [...butLast, last] = [1, 2, 3, 4, 5];
// 报错
复制代码
(4)字符串 tip:扩展运算符还能够将字符串转为真正的数组。
[...'hello']
// [ "h", "e", "l", "l", "o" ]
复制代码
(5)实现了 Iterator 接口的对象 tip:querySelectorAll方法返回的是一个NodeList对象。 它不是数组,而是一个相似数组的对象。 这时,扩展运算符能够将其转为真正的数组。
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
复制代码
tip:方法用于将两类对象转为真正的数组: 相似数组的对象(array-like object)和可遍历(iterable)的对象【(包括 ES6 新增的数据结构 Set 和 Map).】
所谓相似数组的对象,本质特征只有一点,即必须有length属性。
所以,任何有length属性的对象,均可以经过Array.from方法转为数组.
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
复制代码
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
复制代码
tips:将指定位置的成员复制到其余位置(会覆盖原有成员),而后返回当前数组
target(必需):从该位置开始替换数据。若是为负值,表示倒数。
start(可选):从该位置开始读取数据,默认为 0。若是为负值,表示倒数。
end(可选):到该位置前中止读取数据,默认等于数组长度。若是为负值,表示倒数。
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5] 三个参数都是数组里读取
复制代码
find() 找出第一个符合条件的数组成员。【只找一个】
findIndex() 方法的用法与find方法很是相似,返回第一个符合条件的数组成员的位置,
能够接受三个参数,依次为当前的值、当前的位置和原数组。
fill方法使用给定值,填充一个数组
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
复制代码
方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法相似
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
该方法的第二个参数表示搜索的起始位置
[1, 2, 3].includes(3, 3); // false
复制代码
flat()嵌套的数组“拉平”,变成一维的数组。该方法返回一个新数组
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
复制代码
无论有多少层嵌套,都要转成一维数组,能够用Infinity关键字做为参数,有空位,flat()方法会跳过空位。
[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
复制代码
flatMap()方法对原数组的每一个成员执行一个函数(至关于执行Array.prototype.map()), 而后对返回值组成的数组执行flat()方法。该方法返回一个新数组,不改变原数组。
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
复制代码
前言:ES6 对它进行了重大升级,本章介绍数据结构自己的改变;
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};
复制代码
const person = {
sayName() {
console.log('hello!');
},
};
person.sayName.name // "sayName"
复制代码
this关键字老是指向函数所在的当前对象,ES6 又新增了另外一个相似的关键字super,指向当前对象的原型对象
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find() {
return super.foo;
}
};
Object.setPrototypeOf(obj, proto);
obj.find() // "hello"
复制代码
比较两个值是否严格相等Object.is()
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
复制代码
用于对象的合并Object.assign()
(1)目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
(2)若是该参数不是对象,则会先转成对象,而后返回。
(3)因为undefined和null没法转成对象,因此若是它们做为参数,就会报错。-----不在首参数,就不会报错
(4)除了字符串会以数组形式,拷贝入目标对象,其余值都不会产生效果
(5)Object.assign方法实行的是浅拷贝-----对象的任何变化,都会反映到目标对象上面
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
const obj = {a: 1};
Object.assign(obj) === obj // true
复制代码
Object.assign方法用处不少
(1)为对象添加属性
class Point { constructor(x, y) { Object.assign(this, {x, y});//等同于 this.x=x;this.y=y } }
(2)为对象添加方法
Object.assign(SomeClass.prototype, {
someMethod(arg1, arg2) {
···
},
anotherMethod() {
···
}
});
复制代码
(3)克隆对象--克隆它继承的值。若是想要保持继承链
function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
复制代码
(4)合并多个对象
const merge =
(...sources) => Object.assign({}, ...sources);
复制代码
(5)为属性指定默认值
返回某个对象属性的描述对象(descriptor)------Object.getOwnPropertyDescriptors()----引入目的:Object.assign()没法正确拷贝get属性和set属性的问题。
Object.setPrototypeOf(),Object.getPrototypeOf()获取设置原型对象
{constructor: ƒ, defineGetter: ƒ, defineSetter: ƒ, hasOwnProperty: ƒ, lookupGetter: ƒ, …}
Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键名
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
复制代码
Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键值。
const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
复制代码
Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键值对数组
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
复制代码
Object.fromEntries()---方法是Object.entries()的逆操做,用于将一个键值对数组转为对象。
Object.fromEntries([
['foo', 'bar'],
['baz', 42]
])
// { foo: "bar", baz: 42 }
复制代码
<script>
const modle = "一切皆对象";
let alerts = ["请你回答Yes Or No", { "selset": "Yes", "Yes": "在弱类型语言JavaScript面前的确有时候一切皆对象" }, { "selset": "No", "No": "同志你还没学透彻啊!" }];
let sheet=["Object.assign",{"info":"目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性"},{"info":"若是该参数不是对象,则会先转成对象,而后返回"},{"info":"因为undefined和null没法转成对象,因此若是它们做为参数,就会报错。-----不在首参数,就不会报错"},{"info":"除了字符串会以数组形式,拷贝入目标对象,其余值都不会产生效果"},{"info":"Object.assign方法实行的是浅拷贝-----对象的任何变化,都会反映到目标对象上面"}]
var name = prompt(modle);
for (let i = 0; i < alerts.length; i++) {
if (Object.is(i, 0)) {
if (Object.is(name, alerts[i + 1]["selset"]) || Object.is(name, alerts[i + 2]["selset"])) {
Object.is(name, alerts[i + 1]["selset"]) ? alert(alerts[i + 1][alerts[i + 1]["selset"]]) : alert(alerts[i + 1][alerts[i + 2]["selset"]]);
} else {
name = window.confirm(alerts[i]);
if (name) {
alert("你很棒帮哦")
}else{
alert("你个菜鸡");
}
}
}else{
Object.assign(alerts,sheet);
alert(alerts[i]["info"]);
}
}
</script>
复制代码
前言: ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型
注意:Symbol函数前不能使用new命令,不然会报错。 let s = Symbol();
这是由于生成的 Symbol 是一个原始类型的值,不是对象。 也就是说,因为 Symbol 值不是对象,因此不能添加属性 。 typeof s 基本上,它是一种相似于字符串的数据类型。 // "symbol"
// 没有参数的状况
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有参数的状况
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
复制代码
let sym = Symbol('My symbol');
"your symbol is " + sym
// TypeError: can't convert symbol to string
复制代码
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
复制代码
symbol.description // "My symbol"
复制代码
写法
let mySymbol = Symbol();
// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';
// 第二种写法
let a = {
[mySymbol]: 'Hello!'
};
// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上写法都获得一样结果
a[mySymbol] // "Hello!"
复制代码
2.风格良好的代码,应该尽可能消除魔术字符串,改由含义清晰的变量代替。
const shapeType = {
triangle: 'Triangle'
};//变量
function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = .5 * options.width * options.height;
break;
}
return area;
}
getArea(shapeType.triangle, { width: 100, height: 100 });
复制代码
Set前言:新的数据结构 Set,它相似于数组,可是成员的值都是惟一的,没有重复的值。
Set自己是一个构造函数,用来生成 Set 数据结构。
例1:const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x=>s.add(x));
例2:const set = new Set([1, 2, 3, 4, 4]);
[...set]
例3:[...new Set('ababbc')].join('')//abc
复制代码
const s = new Set();
1.--- s.add(1);s.add(2);s.add(2);
// 注意2被加入了两次
s.size // 2
2.--- s.has(1) // true
s.has(2) // true
s.has(3) // false
3.--- s.delete(2);
s.has(2) // false
复制代码
1.keys方法和values方法的行为彻底一致
let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.values()) {
console.log(item);
}
// red
// green
// blue
复制代码
2.entries方法返回的遍历器,同时包括键名和键值,因此每次输出一个数组,它的两个成员彻底相等。
for (let item of set.entries()) {
console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
复制代码
3.省略values方法,直接用for...of循环遍历 Set。
let set = new Set(['red', 'green', 'blue']);
for (let x of set) {
console.log(x);
}
// red
// green
// blue
复制代码
4.forEach方法的参数就是一个处理函数。该函数的参数与数组的forEach一致,依次为键值、键名、集合自己
let set = new Set([1, 4, 9]);
set.forEach((value, key) => console.log(key + ' : ' + value))
// 1 : 1
// 4 : 4
// 9 : 9
复制代码
+ 1. 扩展运算符(...)内部使用for...of循环
let set = new Set(['red', 'green', 'blue']);
let arr = [...set];
// ['red', 'green', 'blue']
+ 2. 扩展运算符和 Set 结构相结合,就能够去除数组的重复成员
let arr = [3, 5, 2, 2, 5, 5];
let unique = [...new Set(arr)];// [3, 5, 2]
复制代码
相似于对象,也是键值对的集合,可是“键”的范围不限于字符串,各类类型的值(包括对象)均可以看成键
tips:Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。若是你须要“键值对”的数据结构,Map 比 Object 更合适。
const map = new Map([
['name', '张三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"
复制代码
解释:执行的算法是
const items = [
['name', '张三'],
['title', 'Author']
];
const map = new Map();
items.forEach(
([key, value]) => map.set(key, value)
);
复制代码
实例的属性和操做方法
(1)size 属性
size属性返回 Map 结构的成员总数。
const map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2
复制代码
(2)set(key, value)
set方法设置键名key对应的键值为value,而后返回整个 Map 结构。若是key已经有值,则键值会被更新,不然就新生成该键。
const m = new Map();
m.set('edition', 6) // 键是字符串 m.set(262, 'standard') // 键是数值 m.set(undefined, 'nah') // 键是 undefined
(3)get()
方法读取key对应的键值,若是找不到key,返回undefined。
const m = new Map();
const hello = function() {console.log('hello');};
m.set(hello, 'Hello ES6!') // 键是函数
m.get(hello) // Hello ES6!
复制代码
(4)has\delete\clear
ES6 系列之 defineProperty 与 proxy