二、ES6+整体篇下


11、构造函数

<script>
  // 构造函数:记住!!!它目的是用来创建对象的,那它有什么好处呢??

  // 1、快速创建多个对象(遵守两个规则,函数名首字母大写,创建对象用new)
  function Pig(name,age) {
    this.name = name;
    this.age = age;
  }
  const pig1 = new Pig('wujunjie', 18);
  const pig2 = new Pig('huaxia', 17);

  console.log(pig1,pig2);

  // 2、构造函数里return返回的指无效,不用写return,所有的实际操作都发生在new里

  // 3、实例成员和静态成员
  // 3.1 构造函数创建的对象称为实例对象,实例对象中的属性和方法称为实例成员(实例属性和实例方法)

  // 3.2 构造函数本身的属性和方法被称为静态成员(静态属性和静态方法)
  // 需要注意的是静态成员只能构造函数来访问,静态方法中的this指向构造函数,例如
  Date.now();
  Math.random();

</script>

12、Object内置构造函数

<script>
  // 1、第一种方式
  const o = {
    name: 'wujunjie'
  }
  console.log(o);

  // 2、第二种方式,也是创建一个空对象,1创建对象的本质就是2这种方式
  const j = new Object();
  j.name = 'huaxia';
  console.log(j);

  // 3、第三种方式
  const k = new Object({name: 'xiaoxia'});
  console.log(k);

  // 4、几个内置构造函数
  // 4.1、Object内置构造函数
  // Object常用的静态方法
  // 4.1.1、Object.keys(): 遍历对象中的所有的属性,它的返回值是数组;
  // 4.1.2、Object.values(): 遍历对象中的所有的属性值,它的返回值是数组;
  // 4.1.3、Object.assign(): 用于拷贝对象;
  const jjwu = { name:'佩奇', age: 6, friend: { name: 'ngb', age: '0.6' }};
  const obj = {};
  Object.assign(obj,jjwu);
  console.log(obj);
  jjwu.age = 10;
  jjwu.friend.name = 'newNgb';
  console.log(obj);

  // Object.assign()经常的使用场景
  Object.assign(obj, {
    name: 'jjwu',
    gender: '男',
    face: 'smart'
  })
  console.log(obj);
  // 需要注意的是相同名称属性直接覆盖
  // 还有一个需要注意的是Obejct.assign()是浅拷贝,引用类型拷贝的是地址
  jjwu.age = 8;
  jjwu.name = 'newJjwu';
  console.log(obj);

  // 4.1.3、Object.values()与join()的巧妙运用
  // 先给一个对象
  const spec = { size: '40cm*40cm', color: '黑色' };
  // 现在要求给他拼成40cm*40cm/黑色
  const str = Object.values(spec).join('/');
  console.log(str);

	// 4.1.4、Object.entries(),返回一个二维数组,数组里是键值对数组
  const object1 = { a: 'somestring', b: 42, };
	console.log(Object.entries(object1)); // [['a', 'somestirng'], ['b', '42']]
  for (const [key, value] of Object.entries(object1)) {
    console.log(`${key}: ${value}`);
  }
</script>

13、数组的常用方法

<body>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
  </ul>
  <script>
    // 1、Array内置构造函数
    // 1.1、forEach、filter、map由于太过简单不写了

    // 1.2、reduce方法
    // 好好理解一下reduce:  arr.reduce((上一次的值,当前值) => {  }, 初始值);
    const arr = [1, 3, 5];
    const total = arr.reduce((pre, cur) => {
      return pre + cur;
    }, 6)
    console.log(total);
    // 需要注意的是当有初始值的时候首次,pre是6,cur是1;
    // 当没有初始值的时候首次,pre是1,cur是3;

    // reduce 很好的一个例子,很好的解释了,reduce只是走内部的循环逻辑,至于返回什么
    // 是你自己说了算的,你return什么就是什么,只是return的循环逻辑不变
    const newArr = [1, 4, 6, 7].reduce((result, item) => {
      item = item * 2;
      result.push(item)
      return result;
    }, []);

    // 实例:计算薪资
    const newArr1 = [1, 4, 6, 7].reduce((result, item) => {
      item = item * 2;
      result.push(item);
      return result;
    }, []);
    console.log(newArr1);

    const arr1 = [{name: 'zhangsan',salary: 1000},{name: 'jjwu',salary: 100000},{name: 'nanguabing',salary: 2000}]

    const salary = arr1.reduce((pre, cur) => {
      const value = pre + cur.salary;
      return value;
    }, 0)
    console.log(salary)

    // 1.3、join方法
    console.log([2,3,4].join('+'));

    // 1.4、find方法:注意直接返回结果,不会返回数组,而且只找第一个,找到一个就停止,没有找到返回undefined
    const objArr1 = [{name: 'jjwu27'}, {name: 'haha'}, {name: 'jjwu27', age: 18}];
    console.log(objArr1.find(n => n.name === 'jjwu27'));


    // 1.5、every方法:找一个错的,有就返回false, 都没有就返回true
    console.log([true,true,false,true].every(n => n));
    console.log([true,true,true,true].every(n => n));

    // 1.6、some方法: 找一个对的,有就返回true, 都没有就返回false
    console.log([true,false,false,false].some(n => n));
    console.log([false,false,false,false].some(n => n));

    // 1.7、concat方法:不改变原数组,并且是浅拷贝
    const array11 = ['a', 'b', 'c'];
    const array22 = ['d', 'e', 'f'];
    const array33 = array11.concat(array22);
    console.log(array11, array22, array33);

    const array44 = [{name: 'jjwu27'}, 'b', 3];
    const array55 = ['d', {age: 8}, 'f'];
    const array66= array44.concat(array55);
    console.log(array44, array55, array66);
    array44[0].age = 9;
    console.log(array44, array55, array66);

    // 1.8、sort方法:默认排序是将元素转换为字符串,然后按照它们的 UTF-16 码元值升序排序。
    const months = ['March', 'Jan', 'Feb', 'Dec'];
    months.sort();
    console.log(months); // ["Dec", "Feb", "Jan", "March"]
    const array111 = [1, 30, 4, 21, 100000];
    array111.sort();
    console.log(array111); // [1, 100000, 21, 30, 4]
    // 想要正确使用sort,就传一个比较函数进去,sort改变原数组,并且返回的就是原数组
    const numbers = [3, 1, 4, 1, 5];
    const sorted = numbers.sort((a, b) => a - b); // 升序排列,b-a就是降序排列
    console.log(sorted, numbers);
    sorted[0] = 10;
    console.log(numbers[0]);

    // 1.9、splice方法: 可以完成增、删、替换操作,直接改变原数组
    // splice(开始索引, 删除元素个数, 添加的元素个数)

    // 移除索引 2 之前的 0(零)个元素,并插入“drum”和“guitar”
    const myFish1 = ["angel", "clown", "mandarin", "sturgeon"];
    const removed1 = myFish1.splice(2, 0, "drum", "guitar"); // ["angel", "clown", "drum", "guitar", "mandarin", "sturgeon"]

    // 在索引 3 处移除 1 个元素
    const myFish2 = ["angel", "clown", "drum", "mandarin", "sturgeon"];
    const removed2 = myFish2.splice(3, 1); // 运算后的 myFish 是 ["angel", "clown", "drum", "sturgeon"]

    // 在索引 2 处移除 1 个元素,并插入“trumpet”
    const myFish3 = ["angel", "clown", "drum", "sturgeon"];
    const removed3 = myFish3.splice(2, 1, "trumpet"); // 运算后的 myFish 是 ["angel", "clown", "trumpet", "sturgeon"]

    // 从索引 -2 处移除 1 个元素
    const myFish4 = ["angel", "clown", "mandarin", "sturgeon"];
    const removed4 = myFish4.splice(-2, 1); // 运算后的 myFish 是 ["angel", "clown", "sturgeon"]

    // 从索引 2 开始删除所有元素
    const myFish5 = ["angel", "clown", "mandarin", "sturgeon"];
    const removed5 = myFish5.splice(2); // 运算后的 myFish 是 ["angel", "clown"]

    // 1.10、slice方法:截取新的数组,不改变原数组
    const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
    console.log(animals.slice(2)); // ["camel", "duck", "elephant"]
    console.log(animals.slice(2, 4)); // rray ["camel", "duck"]
    console.log(animals.slice(1, 5)); // rray ["bison", "camel", "duck", "elephant"]
    console.log(animals.slice(-2)); // ["duck", "elephant"]
    console.log(animals.slice(2, -1)); // ["camel", "duck"]
    console.log(animals.slice()); // ["ant", "bison", "camel", "duck", "elephant"]


    // 1.11、reverse方法:反转数组,唯一重点就是reverse会改变原数组
    const array1 = ['one', 'two', 'three'];
    console.log(array1);
    const reversed = array1.reverse();
    console.log(reversed);
    console.log(array1);

    // 1.12、findIndex方法:返回满足条件的值的索引,只找满足条件的第一个,没找到就返回-1
    console.log([3,4,6,8,4].findIndex(n => n === 4));
    console.log([3,4,6,8,4].findIndex(n => n === 5));

    // 1.13、Array.from()方法:将伪数组转换为真数组,因为伪数组很多方法不能用,经常用在
    // 获取DOM上,一般我们拿的DOM都是伪数组
    const list = document.querySelectorAll('ul li');
    console.log(list);
    const newList = Array.from(list);
    console.log(newList, list);

    // 1.14、常见的pop()、
    // push()方法可以在数组的末属添加一个或多个元素
    const a = [1, 2];
    a.push(3, 4, 5)
    console.log(a);
    // shift()方法把数组中的第一个元素删除
    // unshift()方法可以在数组的前端添加一个或多个元素
    const b = [1, 2, 3, 4, 5, 6];
    b.unshift(-2, -1, 0)
    console.log(b);
    // pop()方法把数组中的最后一个元素删除
  </script>
</body>

14、字符串的常用方法

<script>
  // 1、字符串的常见方法
  // 1.1、实例属性length用来获取字符串的长度
  
  // 1.2、split()方法:用来将字符串拆分成数组
  const str = 'The quick brown fox jumps over the lazy dog.';
  // 用空格分隔,返回数组
  const words = str.split(' ');
  console.log(words);
  // 不加任何符号,作用是把所有字符分隔开,包括空格,返回数组
  const chars = str.split('');
  console.log(chars);
  // 不分割,返回长度为1的数组
  const strCopy = str.split();
  console.log(strCopy); // ['The quick brown fox jumps over the lazy dog.']


  // 1.3、substring()方法:返回该字符串从起始索引到结束索引(不包括)的部分,如果未提供结束索引,则返回到字符串末尾的部分。
  const str1 = 'Mozilla';
  console.log(str1.substring(1, 3)); // "oz"
  console.log(str1.substring(2)); // "zilla"

  // 1.4、startsWith()方法:检测字符串是否以某字符开头
  const str2 = 'Saturday night plans';
  console.log(str2.startsWith('Sat')); //  true
  // 可以给定索引位置,判断是不是从这个索引开始
  console.log(str2.startsWith('Sat', 3)); // false
  console.log(str2.startsWith('urd', 3)); // true

  // 1.5、includes()方法:方法执行区分大小写的搜索,判断字符串是否包含在另一个字符串中
  const sentence = 'The quick brown fox jumps over the lazy dog.';
  const word = 'fox';
  console.log(sentence.includes(word)); // true
  // 也可以指定一个起始位置
  console.log(sentence.includes(word, 17)) // false
  // 区分大小写
  console.log("Blue Whale".includes("blue")); // false

  // 1.6、toUpperCase()方法: 将字母转换成大写
  // 1.7、toLowerCase()方法:将字母转换成小写
  // 1.8、indexOf()方法:检测字符串是否包含某字符
  const paragraph = 'The quick brown fox jumps over the lazy dog. If the dog barked, was it really lazy?';
  const searchTerm = 'dog';
  const indexOfFirst = paragraph.indexOf(searchTerm);
  console.log(`The index of the first "${searchTerm}" from the beginning is ${indexOfFirst}`);// "The index of the first "dog" from the beginning is 40"
  console.log(`The index of the 2nd "${searchTerm}" is ${paragraph.indexOf(searchTerm, indexOfFirst + 1)}`);// "The index of the 2nd "dog" is 52"

  // 1.9、endsWith()方法: 检测字符串是否以某字符结尾
  // 1.10、replace()方法:字符串替换,支持正则匹配,具体在正则里看哦
  // 1.11、match()方法:查找字符,支持正则匹配,具体在正则里看哦
</script>

15、Number

<script>
  // 1、Number
  // 1.1、用来转换基本类型                  
  console.log(Number('123'));          //  123            
  console.log(Number(''));             //  0    
  console.log(Number('string'));       //  NaN         
  console.log(Number(true));           //  1  
  console.log(Number(false));          //  0     
  console.log(Number(NaN));            //  NaN    
  console.log(Number(undefined));      //  NaN           
  console.log(Number(null));           //  0 
  console.log(typeof NaN);             // number
  console.log(Object.prototype.toString.call(NaN));

  // 1.2、toFixed()方法:以四舍五入的形式,设置保留小数位的长度
  const price = 12.345;
  console.log(price.toFixed(2));

</script>

16、构造函数一些值得注意的地方

<script>
  // 1、构造函数值得注意的地方
  // 1.1、给原型对象添加方法的时候,注意this的使用
  const arr = [1,2,3];
  Array.prototype.max = function() {
    // 这里的this就是数组本身,谁调用,this就是谁
    return Math.max(...this)
  }
  console.log(arr.max());

  // 1.2、每个原型对象都有一个constructor属性,用于指回构造函数的,
  // 简单理解就是指向我的爸爸,用来说明我是谁的儿子,我是谁的原型对象
  // 使用场景????
  // 先创建一个构造函数
  function Star() {

  }
  // 正常来说,我们这样添加愿原型方法
  Star.prototype.sing = function() {
    console.log('我会唱歌');
  }
  Star.prototype.dance = function() {
    console.log('我会跳舞');
  }
  // 我们来看看原型对象里还有constructor么?当然有啦!
  console.log(Star.prototype);


  // 然后我们就想啊,能不能直接一起写呢?于是我们就这样了
  Star.prototype = {
    sing: function() {
      console.log('我会唱歌');
    },
    dance: function() {
      console.log('我会跳舞');
    }
  }

  // 我们来看看原型对象里还有constructor么,已经没有啦!
  console.log(Star.prototype);
  // 做了对象的赋值操作,找不到爸爸了

  // 搜易需要重新指回去哦!!!!!!!!这里很重要!!!!!!!!
  Star.prototype.constructor = Star;
  console.log(Star.prototype); // 找到爸爸啦!
</script>

17、几种常见的浅拷贝

<script>
  // 1、几种常见的浅拷贝:浅拷贝只能拷贝简单类型,复杂类型拷贝的依旧是地址
  // 1.1、Object.assign()

  // 1.2、Array.prototype.concat()

  // 1.3、解构运算符:{...obj1, ...obj2}; [...arr1, ...arr2]

  //2、简单的看下深拷贝
  // 下面实现一下,有助于理解什么是深拷贝,实现深拷贝的方法有很多种
  // 首先你要知道的是,实现深拷贝必须用到递归
  const obj = {
    name: 'jjwu27',
    age: 18,
    grilFriend: {
      name: 'xia',
      age: 17
    }
  }

  function deepCopy(newObj, oldObj) {
    for(let k in oldObj) {
      if(oldObj[k] instanceof Array) {
        newObj[k] = [];
        deepCopy(newObj[k], oldObj[k]);
      } else if(oldObj[k] instanceof Object) {
        newObj[k] = {};
        deepCopy(newObj[k], oldObj[k]);
      } else {
        newObj[k] = oldObj[k];
      }
    }
  }

  const o = {};
  deepCopy(o, obj);
  o.grilFriend.sing = function() {
    console.log('我会唱歌')
  }
  console.log(o, obj);

  // 深拷贝总结:
  // 1、深拷贝要求:拷贝的新旧对象互相不影响
  // 2、需要用到函数递归,遇到对象类型就需要递归
  // 3、先数组后对象,因为数组 instanceof Object 也是正确的

</script>

18、异常

<script>
  // 1、异常处理
  // 1.1、throw抛出异常并终止程序!终止程序!
  function fn(x, y) {
    if(!x || !y) {
      throw new Error('缺少参数!')
    }
    return x + y;
  }
  //console.log(fn());

  // 1.2、try catch 捕获异常
  try {
    const arr = {};
    arr.style.name = 'jjwu27';
  } catch(err) {
    // 这两个对比一下去区别
    console.log(err);
    console.log(err.message);

    // try catch 不会终止程序,如果你想终止程序可以加throw
    throw new Error(err);
    //throw new Error(err.message);
  } finally {
    // 不管你的程序对不对,都一定会执行的代码
    console.log('jjwu27');
    console.log('nanguabing');
  }

</script>

19、this的一些值得注意的点

<body>
  <button>你好</button>
  <script>
    // 1、this涉及的一些有意思的东西
    // 1.1、求最大值
    const arr = [100, 123, 112];
    const max = Math.max.apply(null, arr);
    const min = Math.min.apply(null, arr);
    console.log(max, min);

    // 1.2、bind可以用在那些不立即执行的场景里,它返回的是一个函数,可以当作参数,
    // 而call和apply不行,他们是立即执行并返回结果的,不能将函数作为参数了
    // 所以bind的场景就是我想改变this指向但是我不想立即调用这个函数
    // 下面的例子很有意思,实现:点击btn后,btn禁用,2秒后解禁
    const btn = document.querySelector('button');
    btn.addEventListener('click', function() {
      console.log(this);
      this.disabled = true;
      setTimeout(function() {
        console.log(this);
        // 要知道setTimeout里的this是指向window的
        // 在这个普通的函数里,需要让this指向btn
        this.disabled = false;
      }.bind(this), 2000)
    })

  </script>
</body>

20、类型判断

// 1、toString() 第一选择
let obj = {};
Object.prototype.toString.call(obj) === '[Object Object]'

// 2、constructor
let obj = {};
obj.constructor === Object
let obj = [];
obj.constructor === Array

// 3、instanceof: 使用时注意数组判断也是对象
let obj = {};
obj instanceof Object   // true
let arr = [];
arr instanceof Object   // true

// 4、typeof
let obj = {};
typeof obj === 'object';
typeof undefined === 'undefined';
typeof null === 'object';
typeof true === 'boolean';
typeof 123 === 'number';
typeof 'abc' === 'string';
typeof function() {} === 'function';
typeof {} === 'object';
typeof [] === 'object'; // 注意这个哦

21、WeakMap和WeakSet

// 1、WeakMap和WeakSet
// WeakMap是一种集合类型,其中键必须是对象,并且在没有其他引用时会被垃圾回收
// WeakSet是一种集合类型,其中元素必须是对象,并且在没有其他引用时会被垃圾回收
const wm = new WeakMap();
const obj = {};
wm.set(obj, 'value');
console.log(wm.get(obj)); // value
const ws = new WeakSet();
ws.add(obj);
console.log(ws.has(obj)); // true
// 在这个例子中,我们创建了一个WeakMap和一个WeakSet实例。我们使用set()方法将obj
// 对象添加到WeakMap中,并将值设置为'value'。然后,我们使用get()方法从WeakMap中
// 获取值。类似地,我们使用add()方法将obj对象添加到WeakSet中,并使用has()方法检查
// 集合中是否存在该对象。

// 像我们之前写深拷贝的时候,就可以用这两个来判断,WeakMap用set(obj, true)
// 来装,然后用get(obj)来取值判断是否有;WeakSet用add(obj)装对象,并且用has(obj)
// 判断是否有

// 2、Array.of和Array.from
// Array.of方法用于创建一个由参数组成的新数组,它与Array构造函数不同之处在于,当参数只有一个且为数
// 字时,Array.of会创建一个只包含该数字的数组,而不是创建指定长度的空数组。
// Array.from方法将类似数组或可迭代对象转换为真正的数组,它可以接收第二个参数来进行映射或筛选操作。
const arr1 = Array.of(1, 2, 3);
console.log(arr1); // [1, 2, 3]
const str = 'Hello';
const arr = Array.from(str);
console.log(arr); // 输出: ['H', 'e', 'l', 'l', 'o']
const nums = [1, 2, 3, 4, 5];
const doubled = Array.from(nums, num => num * 2);
console.log(doubled); // 输出: [2, 4, 6, 8, 10]

// 3、将字符串变成数组的方法
const str = 'abcdefg';
// split分割
console.log(str.split(''));
// array.from
console.log(Array.from(str));
// 反射,不一定要用filter还有很多方法
Reflect.apply(Array.prototype.filter,str,[(item)=>{
  return item;
}])
// for循环
const str = 'abcdefg';
const arr = [];
for (let index = 0; index < str.length; index++) {
  arr.push(str[index]);
}
console.log(arr);
// 扩展运算符
const str = 'abcdefg';
const arr = [...str];

// 4、.at和flat
// .at方法用于获取数组指定索引位置的元素,支持负数索引
// flat方法用于将多维数组扁平化为一维数组,可以指定扁平化的层数
 const arr3 = [1, 2, 3, 4, 5];
 console.log(arr3.at(2)); // 3
 const arr4 = [1, [2, [3]]];
 console.log(arr4.flat(2)); // [1, 2, 3]

文章作者: 吴俊杰
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 吴俊杰 !
 上一篇
三、ES6+详情篇—Reflect 三、ES6+详情篇—Reflect
第一次看到反射的时候真的不知道它到底有什么用,觉得它是在做重复的事情。慢慢的我发现其实我不懂它的底层,不懂它的设计思想......
2024-12-03
下一篇 
一、ES6+整体篇上 一、ES6+整体篇上
ES6+有趣且重要,如果你不懂它,那你一定写不出优雅的代码,你也一定看不懂别人写的代码。它是基础也是基石,学起来吧......
2024-12-03
  目录