ES6碎片知识点

Object.defineProperty

  1. GET

用法:回调函数,根据其他相关的属性,动态计算得到当前属性值

  1. SET

用法:回调函数,监视当前属性值的变化,更新其他相关的属性值

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

语法:Object.defineProperty(obj, prop, descriptor)

模版解析

什么是模版?

答:HTML中嵌套js代码

js代码以什么样的形式存在于页面中?

答:两种语法。指令属性和大括号表达式。

变量和函数提升

变量声明提升:通过var定义(声明)的变量,在定义语句之前就可以访问到。

值:undefined

函数声明提升:通过function声明的函数,在声明之前就可以直接调用

值:函数定义(对象),就是可以直接调用。
在这里插入图片描述

注意:函数提升必须是通过function声明的函数,而图中的fn3是通过变量定义的函数,它会先进行变量提升,所以fn3()就会调用失败。

数据类型

  • 基本(值)类型
    • String:任意字符串
    • Number:任意的数字
    • Booleantrue或者false
    • undefinedundefined
    • nullnull
  • 对象(引用)类型
    • Object:任意对象
    • Function:一种特别的对象(可以执行)
    • Array:一种特别的对象(里面的数据都有数值下标,内部数据是有序的)

一个函数和一个一般的对象区别在哪?

答:对象是用来存储数据的;函数是可以执行的对象,它的内部存储的是一段可以执行的代码。

判断

  • typeof
    • typeof返回数据类型的字符串表达式,且字符串都是小写。
    • 可以判断:undefined/数值/字符串/布尔值/function
    • 不可判断:nullobjectobjectArray。因为都返回同一个类型。
  • instanceof
    • 用来判断对象的具体类型
    • A instanceof BA是不是B的实例,所以B是一个构造函数。
  • ===
    • 只可以判断undefinenull。因为undefinenull这两个类型只有一个值。
    • =====的区别:==会做数据转换,===不会,它会判断数据是否完全相等。
var a;
console.log(a);//undefined
console.log(typeof a);//"undefined"
console.log(typeof a === "undefined");//true
console.log(a === undefined);//true
//所以,typeof 和 === 都可以判断 undefined

typeof返回的字符串都是小写:

var b ="ben";
console.log(typeof b === "string");//true
console.log(typeof b === "String");//false

typeof判断数值、字符串、布尔值

var a = 3;
console.log(typeof a === "number");//true
var a = "3";
console.log(typeof a === "string");//true
var a = true;
console.log(typeof a === "bollean");//true

===判断nullundefined

var c = null;
console.log(typeof c);//"object"
console.log(a === null);//true
var d;
console.log(d === undefined);//true

instance:用来判断对象的具体类型

var b1 = {
    
    
    b2: [1, 'abc', console.log],
    b3: function () {
    
    
      console.log('b3')
    }
  }
console.log(b1 instanceof Object, b1 instanceof Array) // true  false
console.log(b1.b2 instanceof Array, b1.b2 instanceof Object) // true true
console.log(b1.b3 instanceof Function, b1.b3 instanceof Object) // true true

补充:typeof还可以判断function类型

console.log(typeof b1.b3==='function') // true
console.log(typeof b1.b2[2]==='function') //true

补充:typeof不可以判断类型objectarray

var a = [1,2,3];
console.log(typeof a);//object

数据类型的问题

undefined与null的区别?

  • undefined代表定义未赋值
  • nulll定义并赋值了, 只是值为null

什么时候给变量赋值为null呢?

  • 初始赋值, 表明变量将要赋值为对象。因为null也是个对象。
  • 结束前, 让对象成为垃圾对象(被垃圾回机制回收,这个垃圾回收机制在浏览器中)

严格区别变量类型与数据类型?

数据的类型

  • 基本类型
  • 对象类型
    变量的类型(变量内存值的类型,因为js是个弱类型的语言,通过var定义的变量,本身是没有类型的,而有时候判断变量的类型,其实是判断变量值的类型。)
  • 基本类型: 保存就是基本类型的数据
  • 引用类型: 保存的是地址值

什么是实例?

// 实例: 实例对象
// 类型: 类型对象
function Person (name, age) {
    
    // 构造函数  类型
    this.name = name
    this.age = age
}
var p = new Person('tom', 12) // 根据类型创建的实例对象

数组的解构

var arr = ['张三','李四','王武']
const [name1, name2, name3] = arr

对象的几种创建模式

Object构造函数模式

实现:先创建空Object对象, 再动态添加属性/方法

代码:

// 先创建空Object对象
var p = new Object()
p = {
    
    }
// 再动态添加属性/方法
p.name = 'Tom'
p.age = 12
p.setName = function (name) {
    
    
  this.name = name
}

适用场景: 起始时不确定对象内部数据

缺点:语句太多

对象字面量模式

实现:使用{}创建对象, 同时指定属性/方法

代码:

var p = {
    
    
    name: 'Tom',
    age: 12,
    setName: function (name) {
    
    
      this.name = name
    }
}

适用场景: 起始时对象内部数据是确定的

缺点: 如果创建多个对象, 有重复代码

var p2 = {
    
      //如果创建多个对象代码很重复
    name: 'Bob',
    age: 13,
    setName: function (name) {
    
    
      this.name = name
    }
 }

工厂模式

实现:通过工厂函数动态创建对象并返回

代码:

function createPerson(name, age) {
    
     //返回一个对象的函数===>工厂函数
    var obj = {
    
    
      name: name,
      age: age,
      setName: function (name) {
    
    
        this.name = name
      }
    }
    return obj
}
// 创建2个人
var p1 = createPerson('Tom', 12)
var p2 = createPerson('Bob', 13)
// p1/p2是Object类型

适用场景: 需要创建多个对象

缺点: 对象没有一个具体的类型, 都是Object类型

自定义构造函数模式

实现:自定义构造函数, 通过new创建对象

代码:

//定义类型
function Person(name, age) {
    
    
  this.name = name
  this.age = age
  this.setName = function (name) {
    
    
    this.name = name
  }
}
var p1 = new Person('Tom', 12)
p1.setName('Jack')

适用场景: 需要创建多个类型确定的对象

缺点: 每个对象都有相同的数据, 浪费内存

构造函数+原型的组合模式

实现:自定义构造函数, 属性在函数中初始化, 方法添加到原型上

代码:

function Person(name, age) {
    
     //在构造函数中只初始化一般函数
    this.name = name
    this.age = age
}
Person.prototype.setName = function (name) {
    
    
    this.name = name
}
var p1 = new Person('Tom', 23)
var p2 = new Person('Jack', 24)
console.log(p1, p2)

适用场景: 需要创建多个类型确定的对象

ES5相关扩展

JSON

  • JSON.stringify(obj/arr):把原生js对象(数组)转换为json对象(数组)
  • JSON.parse(json):把json对象(数组)转换为js对象(数组)

注意:JSON对象和JSON数组,而平时所说的JSON字符串是JSON对象和JSON数组的数据类型,即JSON对象和JSON数组都是string类型

分析:

var obj = {
    
    
    name: 'kobe',
    age: 39
};
//把原生的 js 对象转化为 JSON 对象
objJSON = JSON.stringify(obj)
console.log(typeof objJSON)//string 
console.log(objJSON)// {"name":"kobe","age":39}
//把JSON对象转化为原生 js 对象
obj = JSON.parse(objJSON)
console.log(obj)//object

var str = "我是字符串"
console.log(str)//我是字符串
//把原生的 js 字符串转化为 JSON 字符串
strJSON = JSON.stringify(str)
console.log(strJSON)//"我是字符串"

var arr = [1,2,3]
//把原生 js 数组转化为 JSON 数组
arrJSON = JSON.stringify(arr)
console.log(typeof arrJSON)//string

Object扩展

  • Object.create(prototype, [descriptors])

    作用:以指定对象为原型创建新的对象;为新的对象指定新的属性, 并对属性进行描述

    • value : 指定值
    • writable : 标识当前属性值是否是可修改的, 默认为false
    • configurable: 标识当前属性是否可以被删除 默认为false
    • enumerable: 标识当前属性是否能用for in 枚举 默认为false

    代码:

    var obj1 ={
          
          
      name: 'kobe',
      age: 18
    }
    var obj2 = {
          
          }
    obj2 = Object.create(obj1, {
          
          
      sex:{
          
          
        value: '男',
        writable: true,
        configurable: false,
        enumerable: true
      }
    })
    
  • Object.defineProperties(object, descriptors)

    作用:为指定对象定义扩展多个属性

    • get :用来获取当前属性值得回调函数
    • set :监听当前属性值得触发的回调函数,并且实参即为修改后的值

    代码:

    var obj2 = {
          
          
                firstName: 'curry',
                lastName: 'stephen'
            };
    Object.defineProperties(obj2, {
          
          
      fullName: {
          
          
        get: function() {
          
           //获取扩展属性的值。获取扩展属性的值的时候,get方法自动调用
          return this.firstName + '-' + this.lastName
        },
        set: function(data) {
          
          //监听扩展属性,当扩展属性发送变化的时候自动调用。自动调用后,会将变化的值作为实参注入到set函数
          var names = data.split('-');
          this.firstName = names[0];
          this.lastName = names[1];
        }
      }
    });
    console.log(obj2.fullName);//curry-stephen
    obj2.firstName = 'tim';
    obj2.lastName = 'duncan';
    console.log(obj2.fullName);//tim-duncan
    obj2.fullName = 'kobe-bryant';
    console.log(obj2.fullName);//kobe-bryant
    

Function的扩展

Function.prototype.bind(obj):将函数内的this绑定为obj, 并将函数返回

问:区别bind()call()apply()?

  • 都能指定函数中的this

  • call()/apply()是立即调用函数

  • bind():绑定完this不会立即调用当前的函数,而是将函数返回,所以通常用bind()来指定回调函数的this,因为回调函数最终什么时候调用不是我们能决定的,再有就是,回调函数也不是一上来就调用的

  • bind()传递参数的方式和call()一样

    function fun(age) {
          
          
      this.name = 'kobe';
      this.age = age;
    }
    var obj = {
          
          };
    fun.bind(obj, 12)();
    console.log(obj.name, obj.age);//kobe 12
    
  • call()apply()的区别:在不传参数的情况下,二者使用的方式是一样的;如果传递参数了,则call()里面传递的参数可以一个一个传,但是apply()里面传递的参数要放到一个数组里面传
    在这里插入图片描述

let和const

let:与var类似, 用于声明一个变量

特点:在块作用域内有效;不能重复声明;不会预处理, 不存在变量提升,预处理的过程就是变量提升

应用:循环遍历加监听,因为let有自己的块级作用域

const:定义一个常量

特点:不能修改;其它特点同let

应用:保存不用改变的数据

解构赋值

理解:从对象或数组中提取数据, 并赋值给变量(多个)

  • 对象的解构赋值

    let obj = {
          
          name : 'kobe', age : 39};
    let {
          
          name, age} = obj;
    console.log(name,age);
    
  • 数组的解构赋值

    let arr = [1, 'abc', 23, true];
    let [a, b, c, d] = arr;
    let [, , a b ] = arr
    console.log(a, b, c, d);//1, 'abc', 23, true
    
  • 用途:给多个形参赋值

箭头函数

作用:定义匿名函数

基本语法:

  • 没有参数: () => console.log(‘xxxx’)
  • 一个参数: i => i+2
  • 大于一个参数: (i,j) => i+j
  • 函数体不用大括号: 默认返回结果
  • 函数体如果有多个语句, 需要用{}包围,若有需要返回的内容,需要手动返回

使用场景:多用来定义回调函数

箭头函数的特点:

  • 简洁
  • 箭头函数没有自己的this,箭头函数的this不是调用的时候决定的,而是在定义的时候处在的对象就是它的this
  • 扩展理解: 箭头函数的this看外层的是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有,则this是window。

深度克隆

拷贝数据:

  • 基本数据类型:拷贝后会生成一份新的数据,修改拷贝以后的数据不会影响原数据
  • 对象/数组:拷贝后不会生成新的数据,因为拷贝的是引用,所以修改拷贝以后的数据会影响原来的数据

拷贝数据的方法:

  1. 直接赋值给一个变量。(浅拷贝)
  2. Object.assign()。(浅拷贝)
  3. Array.prototype.concat()。(浅拷贝)
  4. Array.prototype.slice()。(浅拷贝)
  5. JSON.parse(JSON.stringify())。(深拷贝/深克隆,但是这种方法,拷贝的数据里面不能有函数,因为JSON的这些方法处理不了函数。)

浅拷贝(对象/数组)的特点:拷贝的是引用,所以修改拷贝以后的数据会影响原数据,使得原数据不安全。

深拷贝(深度克隆)的特点:拷贝的时候会生成新数据,修改拷贝以后的数据不会影响原数据。

思考:如何实现深度拷贝(深度克隆)?

答:因为拷贝的数据里面有对象/数组,所以导致了浅拷贝,所以解决方法就是让数据里面没有对象/数组。那如果数据里面就是有对象/数组,该怎么办呢?那就继续遍历对象/数组,拿到其中的每一个值,一直到拿到的都是基本数据类型的时候,再去复制,也就没有浅拷贝,都是深度拷贝了。

准备知识:

判断数据类型:Object.prototype.toString.call(obj)

截取数据:Object.prototype.toString.call(obj).slice(8,-1)

for in循环:枚举对象时,输出的是属性名;枚举数组时,输出的是下标

定义检测数据类型的功能函数:

function checkedType(target){
    
    
		return Object.prototype.toString.call(target).slice(8,-1)
}

实现深度拷贝(更多针对的是数组或者对象):

function deepClone(target) {
    
    
    let result, targetType = checkedType(target);
    if(targetType === 'Object'){
    
    
      result = {
    
    };
    }else if(targetType === 'Array'){
    
    
      result = [];
    }else {
    
    
      return targetType; // 如果是其他数据类型不复制,直接将数据返回
    }
    // 遍历目标数据
    for(let i in targetType){
    
    
      //获取遍历数据结构的每一项值
      let value = target[i];
      //判断目标结构里的每一项值是否存在对象/数组
      if(checkedType(value) === "Object" || checkedType(value) === 'Array'){
    
    
        //继续遍历获取到的 value 值
        result[i] = deepClone(value);
      }else {
    
    //获取到的 value 值是基本的数据类型或者函数
        result[i] = value;
      }
    }
    return result;
  }

猜你喜欢

转载自blog.csdn.net/qq_41769706/article/details/107523651