附上一篇文章:www.cnblogs.com/soyxiaobi/p…
面向对象编程介绍
面向对象特征:封装性、继承性、多态性
ES6中的类和对象
1.创建类(ES6之前的创建对象 方法见之前js的笔记)
类名首字母大写
创建类 类名后面不要加小括号 ; 生成示例 类名后面加小括号
多个函数方法之间不需要添加逗号
class Star {
//构造函数constructor
constructor(uname,age) {
//类中的函数不需要加function
this.uname = uname;
this.age = age
}
sing() { //添加方法
console.log('我唱歌');
}
}
var ldh = new Star('刘德华',30);
ldh.sing();
2.类的继承
class Father {
constructor(){
}
money() {
console.log('100块钱');
}
}
class Son extends Father {
}
var son = new Son();
son.money(); //son继承了father里面的方法(儿子继承了爹的一百块钱)
super 关键字
用于访问和调用对象父类上的函数,可以调用父类的构造函数,也可以调用父类的普通函数
class Father {
constructor(x,y){
this.x = x;
this.y = y;
}
sum() {
console.log(this.x +this.y);
}
}
class Son extends Father {
constructor(x,y){
super(x,y); //调用父类的constructor,才能把x y赋值给父类构造函数,才能调用sum
}
}
var son = new Son(1,2);
son.sum();
继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的方法。如果子类没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)
class Father {
say() {
return '我是爸爸';
}
}
class Son extends Father {
say() {
console.log('我是儿子');
console.log(super.say() + '的儿子'); //super调用父类的普通函数
}
}
var son = new Son();
son.say();
**注意:**子类在构造函数中使用super,必须放在this前面(必须先调用父类的构造方法,再使用子类构造方法)
3.ES6中类和对象的三个注意点
- 在ES6中类没有变量提升,所以必须先定义类,才能通过类实例化对象
- 类里面的共有的属性和方法一定要加this使用
- 类里面的this指向问题:constructor里面的this指向实例对象,方法里面的this指向这个方法的调用者,在这些方法里可以用that
构造函数和原型
1.构造函数
JavaScript的构造函数中可以添加成员。在构造函数本身上添加的成员叫做静态成员,只能由构造函数本身来访问。在构造函数内部用this创建的成员叫实例成员,只能由实例化的对象来访问。
function Star (uname,age) {
this.uname = uname;
this.age = age;
this.sing = function() {
console.log('我会唱歌');
}
}
var ldh = new Star('刘德华',18); //uname age sing就是实例成员
console.log(ldh.uname); //只能通过实例化对象ldh来访问
ldh.sing();
Star.sex = '男';
//静态成员只能通过构造函数来访问
console.log(Star.sex);
//不能通过对象来访问
console.log(ldh.sex); //undefined
构造函数创建对象很好用,但是存在浪费内存 的问题(相同函数却要各自开辟一个空间存放)
2. 构造函数原型 prototype 与对象原型__proto__
构造函数通过原型分配的函数是所有对象所共享的。
JS中规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意这个prototype就是一个对象,这个对象里面的所有属性和方法,都被构造函数所拥有。
我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法。
function Star (uname,age) {
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var ldh = new Star('刘德华',18);
var zxy = new Star('张学友',19);
ldh.sing(); //可以正常输出
console.log(ldh.sing === zxy.sing);//true
//一般情况下,我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象的身上
对象都会有一个属性__proto__ 指向构造函数的prototype原型对象。之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为__proto__原型的存在。
__proto__对象原型和原型对象prototype是等价的
//接上一个代码块
console.log(ldh.__proto__ === Star.prototype); //true
方法的查找规则:先看ldh对象身上是否有sing方法,如果没有,因为__proto__的存在,就去
构造函数原型对象prototype身上去找sing方法
3.constructor构造函数
对象原型(__proto__)和构造函数(prototype)原型对象 里面都有一个属性constructor属性,constructor我们称为构造函数,因为它指回构造函数本身。
function Star (uname,age) {
this.uname = uname;
this.age = age;
}
--------------------------------------------------
Star.prototype.sing = function() {
console.log('我会唱歌');
}
Star.prototype.movie = function() {
console.log('我会演电影');
}console.log(Star.prototype.constructor);
console.log(ldh.__proto__.constructor); //依旧会指向构造函数Star
-------------------------------------------------
Star.prototype = { //此时prototype被自己写的对象覆盖掉了,constructor也没了
constructor:Star; //所以需要手动将constructor指回构造对象
sing:function(){
console.log('我会唱歌');
},
movie:function(){
console.log('我会演电影');
}
}
4.构造函数、实例、原型对象三者之间的关系
5.原型链
JS的成员查找机制
- 首先看这个对象本身有没有该属性(或者方法)
- 如果没有,就看他的原型(对象的__proto__指向的prototype原型对象)
- 如果还没就去查找原型对象的原型(Object的prototype)
- 以此类推直到找到null
6.原型对象中的this指向
在构造函数中,里面的this指向的是实例对象
在原型对象函数里的this,指向的还是实例对象
function Star (uname,age) {
this.uname = uname;
this.age = age;
}
var that;
Star.prototype.sing = function(){
console.log('我会唱歌');
}
var ldh = new Star('刘德华',18);
// 构造函数中,this指向的是对象实例ldhldh.sing();
//原型对象函数中的this,指向的也是对象实例ldh console.log(that === ldh); // ture
7. 扩展内置对象
可以通过原型对象,对原来的内置对象进行自定义扩展。比如给数组增加自定义求和的功能。(只能用Array.prototype.xxx = function(){}的方式
console.log(Array.prototype);Array.prototype.sum = function() { var sum = 0; for(var i = 0;i< this.length;i++){ sum += this[i]; } return sum;}var arr = [1,2,3];console.log(arr.sum());
继承
ES6之前没有给我们提供extends继承。我们可以通过构造函数+原型对象模拟继承,被称为组合继承。
1.call()
调用这个函数,并且修改函数运行时的this指向
fun.call(thisArg,arg1,arg2,...)
thisArg:当前调用函数this的指向对象
arg1,arg2 :传递的其他参数
function fn() {
console.log('我想喝拿铁咖啡');
console.log(this);
}
var o = {
name:'andy'
};
fn.call(); // this指向window
fn.call(o); //this指向对象o
2.继承
通过call()把父类型的this指向子类型的this,实现子类型继承父类型的属性
function Father(uname,age) {
//this指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
function Son(uname,age) { //this指向子构造函数的对象实例
Father.call(this,uname,age);
}
var son = new Son('刘德华',18);
console.log(son);
继承父类的方法:让子类的prototype指向父类的一个实例对象
function Father(uname,age) { //this指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function() { //父类型的方法
console.log(100000);
}
function Son(uname,age) { //this指向子构造函数的对象实例
Father.call(this,uname,age);
}
Son.prototype = new Father(); //让子类的prototype指向一个新建的父类的实例对象
//如果利用对象的形式修改了原型对象,别忘了利用constructor指回原来的构造函数
Son.prototype.constructor = Son;
Son.prototype.exam = function() {//这是子类独有的方法 且不影响父类
console.log('孩子要考试啦');
}
var son = new Son('刘德华',18);
console.log(son);
console.log(Father.prototype);
console.log(Son.prototype.constructor);
这个例子中原型链:实例对象son.__proto__ -> Son.prototype -> Father.prototype -> Object.prototype -> null
3.ES5中新增的方法
数组方法:forEach() map() filter() some() every()
字符串方法: trim() 去除左右两侧的空格
对象方法:Object.keys() 用于获取对象自身所有属性;
defineProperty()用于定义新属性或者修改原有的属性
4. 各种继承方式
1.原型链继承:将父类实例作为子类的原型
优点:父类中的方法可以复用
缺点:
-
创建子类实例的时候,不能传父类的参数(比如name,不同子类的name不会因为参数不同而不同)
-
子类实例共享了父类构造函数的引用属性,如arr
-
无法实现多继承
function parent(name) { this.name = name || '父亲'; this.arr = [1]; } Parent.prototype.say = function(){ console.log('hello'); } function Child(like) { this.like = like; }
Child.prototype = new Parent(); //核心 Child.prototype.constructor = Child; //核心
let boy1 = new Child(); let boy2 = new Child();
//缺点1:不能向父类构造函数传参 cconsole.log(boy1.name, boy2.name, boy1.name === boy2.name); // 父亲,父亲,true
//缺点2: 子类实例共享了父类构造函数的引用属性,比如arr boy1.arr.push(2); console.log(boy2.arr); //[1,2] 对boy1操作,boy2的arr也会改变
2.借用构造函数
核心: 子类构造函数里用父类构造函数加call
优点:
- 创建子类实例,可以向父类构造函数传参
- 子类实例不共享父类构造函数的引用属性,如arr
- 可以实现多继承(通过多个call或者apply继承多个父类)
缺点:
-
父类的方法不能复用:由于方法在父类构造函数中定义,导致方法不能复用(因为每次创建子类实例都要创建一遍方法)比如say方法。方法应该要复用、共享
-
子类实例,继承不了父类原型上的属性(因为子类的prototype没有指向父类的
function Parent(name) { this.name = name || '父亲'; this.arr = [1]; this.say = function (){ console.log('hello'); } }
function Child(name,like) { Parent.call(this,name); //核心 this.like = like; }
let boy1 = new Child('小红','Apple'); let boy2 = new Child('小明','orange');
//优点1:可以向父类构造函数传参 cconsole.log(boy1.name, boy2.name, boy1.name === boy2.name); // 小红,小明,false
//优点2: 子类实例不共享了父类构造函数的引用属性,比如arr boy1.arr.push(2); console.log(boy1.arr,boy2.arr); //[1,2] [1]
//缺点1:方法不能复用 console.log(boy1.say === boy2.say) //false boy1和boy2的say方法是独立的 不是共享的
//缺点2:不能继承父类原型上的方法 Parent.prototype.walk = function(){ console.log('我会走路'); } boy1.walk; //undefined 说明实例不能获取父类原型上的方法
方法3:组合继承
核心:1.借助父类构造函数,2.将父类实例作为子类原型(即上面两种方法均使用)
优点:
- 保留构造函数的优点:创建子类实例,可以向父类构造函数传参
- 保留原型链的优点:父类方法定义在父类的原型对象上,可以实现方法复用。
缺点:
由于调用了两次父类的构造方法,会存在多余的一份父类实例属性。
function parent(name) {
this.name = name || '父亲';
this.arr = [1];
}
Parent.prototype.say = function(){
console.log('hello');
}
functioin Child(name,like){
Parent.call(this,name); //核心,第一次调用
this.like = like;
}
Child.prototype = new Parent(); //核心 第二次调用
Child.prototype.constructor = Child //修正constructor的指向
let boy1 = new Child('小红','Apple');
let boy2 = new Child('小明','orange');
//优点1: 可以向父类构造函数传参数
cconsole.log(boy1.name, boy1.like); // 小红,apple
///优点2: 可以复用父类原型上的方法
cconsole.log(boy1.say === boy2.say) //true
//优点3: 不共享父类的引用属性,如arr
boy1.arr.push(2);
console.log(boy1.arr, boy2.arr); // [1,2] [1]
//缺点1:由于调用了两次父类的构造方法 会存在一份多余的父类的实例属性
方法4:组合继承优化
核心: 砍掉父类的实例属性,让子类的原型直接指向父类的原型
优点:
- 只调用一次父类的构造函数
- 保留构造函数的优点
- 保留原型链的优点
缺点:
-
修正构造函数的指向之后,父类实例的构造函数指向,同时也发生了改变
function parent(name) { this.name = name || '父亲'; this.arr = [1]; } Parent.prototype.say = function(){ console.log('hello'); } functioin Child(name,like){ Parent.call(this,name); //核心,唯一一次调用 this.like = like; } Child.prototype = Parent.prototype //核心 子类原型和父类原型,实质上是同一个 let boy1 = new Child('小红','Apple'); let boy2 = new Child('小明','orange'); let p1 = new Parent('小爸爸');
//优点1:可以向父类构造函数传参数 console.log(boy1.name , boy1.like) //小红,Apple //优点2:可以复用父类原型上的方法 console.log(boy1.say === boy2.say) //true
//缺点1:当修复子类构造函数的指向后,父类实例的构造函数指向也会跟着改变
没修复以前: console.log(boy1.constructor); //Parent 修复代码: Child.prototype.constructor = Child; 修复之后: console.log(boy1.constructor); //Child console.log(p1.constructor); //Child(父类的也被改了)
方法5: 寄生组合继承 ---完美方式
function Parent(name) {
this.name = name || '父亲';
this.arr = [1];
}
Parent.prototype.say = function() {
console.log('hello');
}functioin Child(name,like){
Parent.call(this,name); //核心
this.like = like;
}
//核心 通过创建中间对象,子类原型和父类原型就会隔离开,有效避免方法4的缺点
Child.prototype = Object.create(Parent.prototype);//这里是修复构造函数指向的代码
Child.prototype.constructor = Child
let boy1 = new Child('小红','apple');
let boy2 = new Child('小明','orange');
let p1 = new Parent('小爸爸');
函数进阶
1.函数定义方式
//1.自定义函数(命名函数)
function fn() {};
//2.函数表达式(匿名函数)
var fun = function(){};
//3.利用new Function('参数1','参数2',...,'函数体'); //仅供了解
var fn = new Function('a','b','console.log(a + b)');
fn(1,2);
//所有函数都是 Function的实例
2.this指向问题
改变函数内部this指向:
bind() call() apply()
1)call() 略
2)apply()
fn.apply(thisArg,[argsArray])
thisArg:在fn函数运行时指定的this值
argsArray:传递的值 必须包含在数组里面
返回值就是函数的返回值,因为它就是调用函数
var o ={
name: 'andy';
}
function fn(uname) {
console.log(this);
console.log(uname); //'ldh'
};
fn.apply(o,['ldh']);
//1.也是调用函数 也可以改变this指向
//2.但他的参数必须是数组(伪数组)
//3.apply主要应用 比如可以利用apply借助于数学内置对象求最大值
var arr = [1,66,3,99,4];
var max = Math.max.apply(Math,arr);
console.log(max); //99
3) bind()
fn.bind(thisArg,arg1, arg2,...)
参数同call() 但bind()方法不会调用函数,能改变this指向
返回由指定的this值和初始化参数改造后的原函数拷贝
var o = { name: 'andy',}function fn(uname) { console.log(this); console.log(uname); //'ldh'};var f = fn.bind(o,'wbh');f();
// 返回的是原函数改变this之后产生的新函数
//如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this,此时用bind
//例 有一个按钮,点击之后禁用三秒 之后开启
var btn = document.querySelector('button');
btn.onclick = function(){
this.disabled = true; //this指向btn
setTimeout(function() {
this.disabled = false;
}.bind(this),3000) //这个this指向btn 使得上一行的this也指向btn
}
严格模式
严格模式可以分为 整个脚本 和个别函数的严格模式。IE10以上支持
1.开启严格模式
1)为脚本开启严格模式
在所有语句前放一个特定的语句 'use strict';
2)为某个函数开启严格模式
function fn(){
'use strict';
//下面的代码按照严格模式执行
}
2.严格模式中的变化
- 变量和this规定
- 正常模式里,如果变量没声明就赋值,默认是全局变量。严格模式必须先用var命令声明 才能使用
- 严禁删除已经声明的变量 delete x;语法是错误的
- 严格模式下 全局作用域中的this是undefined 而不是window
- 严格模式下 如果构造函数不加new调用 this会报错(普通模式下不加new也可以,只不过当做普通函数,this指向全局对象)
- 严格模式下,定时器里面的this指向的还是window
- 严格模式下,一个函数里面不能有重名的参数,
- 严格模式下,不允许在非函数的代码块内声明函数(比如for循环,if)
高阶函数
高阶函数是对其他函数进行操作的函数,它接受函数作为参数或者将函数作为返回值输出。
function fn(a, callback){ console.log(a); callback && callback();}fn(1,function(){ console.log('我是最后调用的');})//接受函数作为参数
闭包
闭包指有权访问另一个函数作用域中变量的函数
被访问的局部变量所在的函数就是闭包
闭包的主要作用:延伸了变量的作用范围
function fn(){
var num = 10;
function fun() { //fun访问了fn中的局部变量 num 所以fun是个闭包
console.log(num);
}
return fun;
}
var f = fn(); //此时fn外面的作用域就可以通过fun访问fn的局部变量num
f();
浅拷贝和深拷贝
浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用
深拷贝拷贝多层,每一层的数据都会拷贝
var obj = {
id:1,
name:'andy',
msg:{
age:18
}
};
var o = {};
for (var k in obj){
o[k] = obj[k];
}
Object.assign(o,obj);//assign方法,浅拷贝的方法
console.log(o); //此时o就是obj的浅拷贝 里面的msg是同一块内存地址
深拷贝:
function deepCopy(newobj,oldobj){
for(var k in oldobj){
var item = oldobj[k];
if (item instanceof Array){
newobj[k] = [];
deepCopy(newobj[k],item)
} else if (item instanceof Object){
newobj[k] = {};
deepCopy(newobj[k],item)
} else {
newobj[k] = item;
}
}
}
ES6
1.let
let声明的变量只能在所处于的块级作用域使用
块级作用域即一对大括号包含的区域
if (true) {
let a = 10;
}
console.log(a); //undefined
注意:使用let声明的变量才具有块级作用域,var声明的变量不具备块级作用域
//防止循环变量变成全局变量
for(let i = 0;i<2;i++){ //let i也跟这个for的块级作用域绑定
}
console.log(i);//访问不到
//let声明每次迭代都会创建一个新变量,并以之前迭代中的同名变量的值将其初始化
//这个特性对于for-of循环和for-in循环来说也是一样的
使用let声明的变量 不存在变量提升
console.log(a); // 报错 a is not defined
let a = 20;
使用let声明的变量 具有暂时性死区特性
var num = 10;
if (true){
console.log(num); // 因为这个if大括号内使用了let再次声明num,所以外面的num不起作用,此时依然报错:初始化前无法访问num
let num = 20; //一旦在块级作用域用let声明变量,变量就会和这个块级作用域暂时绑定
}
面试题:
var arr = [];
for(let i =0;i<2;i++){
arr[i] = function(){
console.log(i);
}}
arr[0](); //0
arr[1](); //1
//let声明每次迭代都会创建一个新变量,并以之前迭代中的同名变量的值将其初始化
//所以arr[0]这个函数所在块级作用域中i是0 arr[1]所在块级作用域中i是1
2.const
声明常量,常量就是值(内存地址)不能变化的量
-
具有块级作用域
-
声明const常量时必须赋初始值
const PI; //报错 缺少了初始值
-
常量赋值后,值不可修改。对于基本数据类型,赋值后不能改值的大小。对于复杂数据类型,赋值后不能更换内存地址,但是可以改数据结构内部的值
const PI = 3.14; PI = 100; //报错 不能给常量修改值
const arr = [100,200]; arr[0] = 'a'; arr[1] = 'b'; console.log(arr); // ['a','b'] arr = ['a','b'] //修改内存地址 不允许 所以报错
let const var 区别
3. 解构赋值
ES6中允许从数组中提取值,按照对应位置,对变量赋值。对象也可以实现解构。
数组解构
let [a,b,c] = [1,2,3]; //按照一一对应的关系
console.log(a);
console.log(b);
console.log(c);
let arr = [1,2,3]
let [a,b,c] = arr;
----------------------------
//如果不是一一对应
let [foo] = []; //foo 为undefined
let [bar,foo] = [1]; //foo 为undefined
对象解构 允许使用对象的名字匹配对象的属性
let person = {name:'zhangsan', age:30};
let { name, age} = person; //如果person中有name age 则匹配到 并把值赋值到左边
----------------------------------------------------
let {name:myName} = person; //用name匹配person里面的属性 匹配成功则把属性值赋给变量myName
console.log(myName); //'zhangsan'
4. 箭头函数
() => {} //小括号里放形参 大括号里放函数体
const fn = () => {}
fn();
如果函数体中只有一句代码,且代码的执行结果就是返回值,可以省略大括号
function sum(a,b) {
return a + b;
}
`````````````````````````````````
const sum = (a,b) => a + b;
const result = sum(10,20);
console.log(result); // 30
如果形参只有一个,可以省略小括号
function fn (v) {
return v;
}
````````````````````````````````
const fn = v => v;
箭头函数不绑定this 箭头函数没有自己的this关键字,如果在箭头函数中使用this,this关键字将会指向箭头函数定义位置中的this
function fn() {
console.log(this);
return () => {
console.log(this)
}
}
const obj = {name:'zhangsan'};
const resFn = fn.call(obj); //resFn就是上面那个匿名函数
resFn(); //输出的是obj这个对象 因为箭头函数中没有this,不然匿名函数是个普通函数,其this应该是window
箭头函数面试题
var age = 100;
var obj = {
age:20,
say:() => {
alert(this)
}}
obj.say(); //100;
//因为obj对象不产生作用域,所以say箭头函数定义在全局作用域下。箭头函数要换成function 就输出20
5.剩余参数
const sum = (...args) => { //形参前加三个点,就表示接受剩余的参数,并存放在一个数组里
let total = 0;
args.forEach(item => {
total += item;
})
return total;
};
sum(10,20);
sum(10,20,30);
剩余参数和解构配合使用
let students = ['wangwu','zhangsan','lisi'];
let [s1, ...s2] = students;
console.log(s1);'wangwu'
console.log(s2); //['zhangsan','lisi']
6.Array的扩展方法
-
扩展运算符 可以将数组拆分成以逗号分隔的参数序列
let ary = [1,2,3]; ...ary // 1,2,3 console.log(...ary); console.log(1,2,3); //两种console.log 结果一样
应用1:合并数组
//方法1
let ary1 = [1,2,3];
let ary2 = [4,5,6];
let ary3 = [...ary1, ...ary2]; // [1,2,3,4,5,6]
//方法2
ary1.push(...ary2);
应用2:将类数组或者可遍历对象转换成真正的数组
let oDivs = document.getElementsByTagName('div');
oDivs = [...oDivs];
-
构造函数方法Array.from()
let arrayLike = { '0':'a', '1':'b', '2':'c', 'length':3 //还非得是索引0,1,2,和length }; let arr2 = Array.from(arrayLike); //['a','b','c']
from方法还可以接受第二个参数,类似于数组中的map方法,用于对每个元素进行处理,将处理后的值放入返回的数组。
let arrayLike = {
"0":1,
"1":2,
"length":2
}
let newAry = Array.from(aryLike, item => item *2); //[2,4]
- 实例方法find()
用于找出第一个符合条件的数组成员,如果没有,则返回undefined
find(function(currentValue,index,arr))
find方法给数组中每一个元素调用测试函数,测试函数返回true时,find()返回符合条件的元素,之后的值不会再调用执行函数
let arr = [{
id:1,
name:'张三'
},{
id:2,
name:'李四'
}];
let target = arr.find(item => item.id == 2);//target是一个对象
- 实例方法findIndex()
用于找到第一个符合条件的数组成员的位置,如果没有 返回-1
let arr = [1,5,10,15];
let index = arr.findIndex(value => value > 9);
console.log(index); // 2
- 实例方法includes()
表示某个数组是否包含给定的值,返回布尔值
[1,2,3].includes(2); //true
[1,2,3].includes(4); //false
7.String 的扩展方法
- 模板字符串
ES6中新增的创建字符串的方式,使用反引号定义。
模板字符串可以解析变量 利用${ }
let name = `张三`;
let sayHello = `hello, my name is ${name}`;
模板字符串中可以换行
let result = {
name:'zhangsan';
age:20;
sex:'男';
}
let html = ` <div>
<span>${result.name}</span>
<span>${result.age}</span>
<span>${result.sex}</span></div>`;
模板字符串中可以调用函数
const sayHello = function () {
return '恭喜RNG在2021年MSI中夺得冠军!';
};
let greet = `${sayHello()}`;
console.log(greet);
- startsWith() endsWith()
表示参数字符串是否在原字符串的头部、尾部 返回布尔值
let str = 'Hello world!';
str.startsWith('Hello'); //true
str.endsWith('!'); //true
- 实例方法repeat()
repeat()方法表示将原字符串重复n次,返回一个新字符串
'x'.repeat(3) //"xxx"
'hello'.repeat(2) //"hellohello"
8.set数据结构
ES6中新的数据结构set,类似于数组,但是成员的值是唯一的,不重复
set本身是一个构造函数,用来生成set数据结构
const s = new Set();
console.log(s.size); // 0
const set = new Set([1,2,3,4,4]); // {1,2,3,4}
//数组去重
const s2 = new Set(['a','a','b','b']);
const ary = [...s2];
console.log(ary); // ['a','b']
set实例方法:
遍历set
跟数组一样用forEach
s.forEach(value => console.log(value))