JS高级-01

87 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情

  • 我们可以通过__proro__(非标准)或Object.getPrototypeOf获取某个实例的原型

  • 我们可以利用call方法借用父构造函数绑定父类的属性(不可以继承父类的方法)

  • 将子构造函数的prototype属性赋值为父构造函数的prototype属性

    • 问题:在修改子构造函数的prototype属性时,会一并把父构造函数的prototype属性给污染了
  • 通过将子构造函数的prototype属性赋值为父类的实例对象时,虽然可以继承父类的方法,但是有个缺点:

    • 如果父构造函数有形参,在创建父类实例时,就不太符合语义
  • 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数

实现继承的最佳方式,可以借助Object.create方法

Object.create 的作用:创建一个对象,并返回,这个对象的原型指向第一个实参

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script>
    // 坚持一种代码风格
    // 每个独立的逻辑块,适当的换行,可以增加代码的可读性
    function Father(uname, age) {
      this.uname = uname
      this.age = age
    }
    Father.prototype.hehe = function () {
      console.log('heheda')
    }
    
    function Son() {
      // Father.call(this)
    }
    // Son.prototype = Father.prototype
    // Son.prototype = new Father()
    // Object.create 的作用:创建一个对象,并返回,这个对象的原型指向第一个实参
    var obj = Object.create(Father.prototype)
    Son.prototype = obj
    Son.prototype.constructor = Son
    
    Son.prototype.haha = function () {
      console.log('haha');
    }
  </script>
</body>

</html>

函数在定义时的参数叫形参,调用时的参数叫实参

class实际就是ES6新出来的语法(语法糖),本质还是function,之前有的特点都有

可以通过extends关键字来实现继承,形如:class Son extends Father { }

数组方法:

  • forEach方法的第一个参数是一个函数,函数的第一个参数是元素,第二个参数才是索引号,与变量名没关系,顺序是固定的
    • 不能写continue、break,return也不能终止循环,想要终止循环,可以用some方法
  • filter方法,是用来过滤数组元素
    • 接收一个函数作为参数,这个函数的第一个形参是元素,第二个形参是索引号
    • 内部会有循环机制,每次循环都会调用函数,如果函数返回true,则保留当前循环元素,如果返回false,则剔除当前循环元素
    • 会返回一个新数组,不会影响原来的数组,我们也称之为非变异方法
  • some方法,是用来看数组中是否存在符合条件的元素(运行机制:内部也有循环机制,每次循环也会调用函数,只要函数返回true,则终止循环,some函数也返回true,若果循环结束,还没有一个返回true,则some函数返回false)
    • 返回值是布尔值,如果有,则返回true,否则返回false
    • 一旦找到符合条件的,则立即终止循环
    • 当循环逻辑比较复杂或耗时时,可以提高一丢丢性能
  • map方法,用来做映射,返回值是数组,内部会有循环机制.........,实参函数的返回值会组成一个新的数组返回
  • every方法,和some类似,但必须每一个都符合条件,才返回true,反之,只要有一个不符合条件,就返回false

非变异方法和变异方法的区别就是看调用完这个方法后,会不会影响原数组,有则是变异方法,无则是非变异方法

写代码时,要逐步测试,不要写了一百行,再来测试,如果报错了,这个时候你很可能懵逼,不知道到底是哪一行代码引起的

forEach和some的区别:

  • forEach不可以通过return终止循环,也不可以使用continue、break
  • some可以通过return true(why? 乌龟的尾巴,死龟腚)终止循环,在只需要找到某个元素时,效率更高

.trim()方法就是去除字符串的前后空格,中间的不会去掉

Object.keys(obj)返回obj对象自身(拿不到原型链上的属性)的所有键名组成的数组

Object.defineProperty方法可以给某个对象添加或修改属性,基本语法:

Object.defineProperty(obj, propertyName, discreptor)

  • obj:操作的对象

  • propertyName:属性名,字符串型

  • discreptor:属性描述符,是对象:

    • value:属性值,默认值是undefined
    • writable:是否可写,默认值是false,不可写(不能被重新赋值)
    • enumerable:是否可枚举(是否可以被for...in或Object.keys()方法获取到键名),默认值是false
    • configurable:是否可配置(是否可以被delete删除或者重新配置属性(重新配置时,会直接报错))
    • get:是一个函数,当访问该属性时,该函数就会执行,函数的返回值就是获取的属性值,默认值是undefined
    • set:是一个函数,当给该属性赋值时,该函数就会执行,函数的第一个形参就是想要赋的值

    补充说明,这里的默认值(writable、enumerable、configurable),说的是通过Object.defineProperty方法添加的属性,如果是通过对象字面量创建的,默认值都是true

    存取描述符范例:

    var obj = { name: '张三', age: 18 }
    
    function setSex(sex) {
        Object.defineProperty(obj, 'sex', {
          	// 取
            get: function () {
                console.log('想要获取sex?哈哈,可以在这里搞点事情')
                return sex === 'male' ? '男' : '女'
            },
          	// 存
            set: function (val) {
                console.log('想要给sex赋值?呵呵,又被拦截到了,也可以在这里搞点事情')
                sex = val
            }
        })
    }
    
    setSex('male')
    

属性描述符分为三种:

  • 公共描述符(enumerable、configurable)
  • 数据描述符(value、writable)
  • 存取描述符(get、set)
  • 注意:数据描述符和存取描述符不能都用,公共描述可以都用

可以通过这个方法获取到某对象的某个属性的描述符:Object.getOwnPropertyDescriptor(obj, propertyName)