JS相关知识学习笔记(二)

1、创建对象的三种方式

(1)字面量的形式创建对象

var obj = {}

(2)使用new关键字创建对象

var obj = new Object()

(3)使用构造函数的方式创建对象(可以看做创建了一个类)

function Animal(name, age) {
    this.name = name
    this.age = age
    this.bark = function() {
        console.log('I like bark')
    }
}
var hsq = new Animal('哈士奇', 5)
hsq.bark()
2、构造函数的实例成员和静态成员

(1)实例成员

  • 构造函数内部使用this添加的成员就是实例成员
  • 实例成员只能通过实例化的对象来访问
function Animal(name) {
    this.name = name
}
var hsq = new Animal('哈士奇')
console.log(hsq.name)  // 访问实例成员

(2)静态成员

  • 在构造函数本身上添加的成员就是静态成员
  • 静态成员只能通过构造函数来访问
function Animal(name, age) {
    this.name = name
    this.age = age
}
Animal.bark = '汪汪汪'  // 添加静态成员
var hsq = new Animal('哈士奇', 5)
console.log(Animal.bark)  // 构造函数访问静态成员

注意:

1、实例对象访问静态资源,或者构造函数访问实例成员,结果都是undefined

2、在没有类的概念之前,使用构造函数来实现类似功能的

3、构造函数存在内存浪费问题,因为每创建一个实例对象,就会在内存中分配一定的内存空间

3、构造函数的原型(对象)prototype
  • 在ES6中,每一个构造函数被创建出来会自动有一个prototype属性(原型对象),不需要自己创建
  • 可以为原型对象上面添加属性和方法,这些属性和方法可以被函数创建的实例对象进行调用,可以看做是公共的属性和方法
function Animal(name, age) {
  this.name = name
    this.age = age
}
// Animal.bark = '汪汪汪' // console.log(hsq.bark)  结果为undefined
Animal.prototype.bark = '汪汪汪'
var hsq = new Animal('哈士奇', 5)
console.log(hsq.bark)   // 结果为 汪汪汪
4、对象原型__proto__
  • 对象身上系统会自己添加一个__proto__(对象原型)属性,这个属性指向构造函数的原型对象,因此实例对象可以使用原型对象所拥有的方法

  • __proto__和prototype是等价的

  • 查找规则:

    实例对象要调用一个属性或方法时,先看自己身上有没有,如果有就用自己的,如果没有,会自己通过__proto__查找原型对象(prototype)中有没有,如果有的话,就可以使用

  • 一般不去使用__proto__修改原型对象所拥有的属性或者方法,强烈不建议

5、constructor构造函数

__proto__prototype中都有一个constructor属性,即构造函数,constructor属性主要记录该对象引用于哪一个构造函数,也可以重新指回构造函数

function Animal(name, age) {
    this.name = name
    this.age = age
}
Animal.prototype = {
  //如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,这样会覆盖掉原型对象中的内容,则必须手动的利用constructor指回原来的构造函数
  constructor: Animal,
  bark: '汪汪汪',
  eat: '吃狗粮'
}
var hsq = new Animal('哈士奇', 5)
console.log(Animal.prototype.constructor)
console.log(hsq.__proto__.constructor)
6、原型链
  • 只要是对象就会有__proto__原型,指向原型对象
  • Animal的对象实例的__proto__属性指向Animal的原型对象,Animal原型对象里面的__proto__指向的是Object原型对象,Object原型对象指向的是null
function Animal(name, age) {
  this.name = name
  this.age = age
}
var hsq = new Animal('哈士奇', 5)
console.log(Animal.prototype)  // {constructor: ƒ}
console.log(Animal.prototype.__proto__ == Object.prototype)  // true
console.log(Object.prototype.__proto__)  // null

任何对象都有原型对象,也就是prototype属性,任何原型对象也是一个对象,该对象就有__proto__属性,这样一层一层往上找,就形成了一条链,即原型链

7、JavaScript成员的查找机制

(1)当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性

(2)如果没有就查找它的原型(也就是__proto__指向的 prototype 原型对象)

(3)如果还没有就查找原型对象的原型(Object的原型对象)

(4)依此类推一直找到 Object 为止(null)

(5)__proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线

(6)如果原型链上的对象都有要找的属性(方法),即遵循就近原则,优先使用自己的

8、原型对象中this的指向

(1)在构造函数中,this指向的是实例对象

(2)原型对象函数里面的this,指向的也是实例对象

9、扩展内置对象(对原来的内置对象进行扩展自定义方法)

数组的原型对象中没有求和的方法,可以自定义扩展

只允许以 . 的方式去添加方法,不可以使用对象的形式,不然会覆盖掉原型对象中的所有方法

Array.prototype.sum = function() {
    var sum = 0
    for (var i = 0; i < this.length; i++) {
        sum += this[i]
    }
    return sum
}

//不允许,会覆盖,内置的原型对象也不允许赋值
// 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, 4]
console.log(arr.sum())  // 10

var arr1 = [11, 22, 33]
congsole.log(arr1.sum())  // 66
10、继承

call(参数1,参数2,…) 参数1为修改后this的指向

1、call( )可以调用函数

2、call( )可以改变this指向

var x = 10
var y = 20
function sum() {
  console.log(this.x + this.y)
}
var obj = {
  x: 100,
  y: 200,
  sum: function() {
    console.log(this.x + this.y)
  }
}
sum()  // 30
sum.call(obj)  // 300

obj.sum()  // 300
obj.sum.call(window)  // 30

借用父构造函数实现继承:借用call( )将父构造函数中的this修改为子构造函数的this

function Father(uname, age) {
  this.uname = uname
  this.age = age
}

function Son(uname, age) {
  Father.call(this, uname, age)
}
var son = new Son('zs', 18)
console.log(son)  // Son {uname: "zs", age: 18}

借用原型对象实现继承:

本质:子类创建的实例拥有父类创建的实例的属性(使用call( )修改this指向),子类创建的实例可以使用父类的公共方法(必须要产生联系)

  • 子构造函数和父构造函数没有任何关系,可以使子原型对象和赋原型对象处于同一条原型链上,这样子原型对象就可以使用父原型对象上的属性和方法了
function Father(uname, age) {
  this.uname = uname
  this.age = age
}
Father.prototype.hi = function() {
  console.log('你好呀')
}

function Son(uname, age) {
  Father.call(this, uname, age)
}

// 直接赋值会有问题,如果子原型对象发生变化,父原型对象也会发生变化
// Son.prototype = Father.prototype  

// 此时将Son的constructor指向Father,需要重新指回Son的构造函数
Son.prototype = new Father() 
Son.prototype.constructor = Son
Son.prototype.exam = function() {
  console.log('考试')
}

var son = new Son('zs', 18)
console.log(son)
son.exam()
son.hi()

ES6之前通过构造函数+原型实现面向对象编程

ES6通过实现面向对象编程

类的本质还是一个函数,类是构造函数的另一种表现形式

(1)类有原型对象prototype

(2)类原型对象prototype里面有constructor指向类本身

(3)类可以通过原型对象添加方法

(4)类创建的实例对象有__proto__原型指向类的原型对象

11、遍历迭代方法(ES5新增)

(1)数组方法

  • array.forEach(function(currentValue, index, array){})——遍历方法

    • forEach的参数为一个函数

    • 函数的参数:

      • currentValue:每一项的值

      • index:每一项的索引

      • Array:数组本身

  • Array.filter(function(currentValue, index, arr){})——筛选过滤方法(批量筛选)

    • filter参数是一个函数

    • 函数的参数:

      • currentValue:每一项的值

      • index:每一项的索引

      • Array:数组本身

    • 返回值是一个数组,该数组保存遍历过程中执行函数返回值为true的值

    var arr = [12, 66, 4, 88]
    var newArr = arr.filter(function(value, index) {
      return value >= 20
    })
    console.log(newArr)  // [66, 88]
    
  • Array.some(function(currentValue, index, arr){})——查找满足条件元素方法(查找某一个)

    • Some参数是一个函数

    • 函数的参数:

      • currentValue:每一项的值

      • index:每一项的索引

      • Array:数组本身

    • 返回值是一个布尔值,遍历过程中,有符合条件的元素,返回true,无符合元素条件,返回false,查找到第一个符合条件的元素就停止查找

    [10, 30, 4].some(function(value) {
      return value >= 20
    })
    console.log(flag)  // true
    

注意:

在forEach、filter里面return不会终止迭代

在some里面return true就是终止遍历,迭代效率更高

2、字符串方法

  • trim( )去除字符串前后的空白字符

    var x = '   abc   '
    x.trim()    // abc(前后无空格)
    // 可用于输入时的空格检测
    
    console.log(x.length)    // 9
    console.log(x.trim().length)   // 9
    // trim()只会去掉字符串两边的空格,并不会改变它的值
    

3、对象方法

  • Object.keys(obj) 获取对象的属性名

    效果类似于for…in

    将所有的属性名获取到之后保存在一个数组中

    可用于判断对象中是否有某个属性

    var obj = {
      id: 1,
      name: 'zs'
    }
    var arr = Object.keys(obj)
    console.log(arr)  // (2)['id', 'name']
    
  • Object.defineProperty(obj, prop, descriptor) 定义新属性或修改原有的属性

    obj:目标对象

    prop:属性名

    descriptor: 描述

            value:属性已有值则修改,没有属性则赋值,默认为undefined
    
            writable:布尔值,目标属性是否允许修改,默认为false
    
            enumerable:布尔值,目标属性是否可以被遍历,默认为false
    
            configurable:不允许被删除或不允许再次修改第三个属性的特性,默认为false
    
    var obj = {
      id: 1,
      name: 'zs'
    }
    Object.defineProperty(obj, 'address', {
      value: '陕西西安',
      writable: false,
      enumerable: false,  // 无法被遍历
      configurable: false
    })
    console.log(obj)
    console.log(Object.keys(obj))
    delete obj.address  // 无法被删除
    console.log(obj)
    

你可能感兴趣的:(JS相关知识学习笔记(二))