JS高级(原型/函数)

原型

Javascript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在 prototype 对象上。

function Person (name, age) {
  this.name = name
  this.age = age
}

console.log(Person.prototype)

Person.prototype.type = 'human'

Person.prototype.sayName = function () {
  console.log(this.name)
}

var p1 = new Person(...)
var p2 = new Person(...)

console.log(p1.sayName === p2.sayName) // => true

这时所有实例的 type 属性和 sayName() 方法, 都是同一个内存地址,指向 prototype 对象,因此就提高了运行效率。

构造函数、实例、原型三者之间的关系

任何函数都具有一个 prototype 属性,该属性是一个对象。

构造函数的 prototype 对象默认都有一个 constructor 属性,指向 prototype 对象所在函数。

通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 __proto__

总结:

  • 任何函数都具有一个 prototype 属性,该属性是一个对象

  • 构造函数的 prototype 对象默认都有一个 constructor 属性,指向 prototype 对象所在函数

  • 通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 __proto__

  • 所有实例都直接或间接继承了原型对象的成员

原型对象的问题

  • 共享数组

  • 共享对象

原型对象使用建议

  • 私有成员(一般就是非函数成员)放到构造函数中

  • 共享成员(一般就是函数)放到原型对象中

  • 如果重置了 prototype 记得修正 constructor 的指向

继承

构造函数的属性继承:借用构造函数

function Person (name, age) {
  this.type = 'human'
  this.name = name
  this.age = age
}

function Student (name, age) {
  // 借用构造函数继承属性成员
  Person.call(this, name, age)
}

var s1 = Student('张三', 18)
console.log(s1.type, s1.name, s1.age) // => human 张三 18

原型继承

function Person (name, age) {
  this.type = 'human'
  this.name = name
  this.age = age
}

Person.prototype.sayName = function () {
  console.log('hello ' + this.name)
}

function Student (name, age) {
  Person.call(this, name, age)
}

// 利用原型的特性实现继承
Student.prototype = new Person()

var s1 = Student('张三', 18)

console.log(s1.type) // => human

s1.sayName() // => hello 张三

函数声明与函数表达式的区别

  • 函数声明必须有名字

  • 函数声明会函数提升,在预解析阶段就已创建,声明前后都可以调用

  • 函数表达式类似于变量赋值

  • 函数表达式可以没有名字,例如匿名函数

  • 函数表达式没有变量提升,在执行阶段创建,必须在表达式执行之后才可以调用

函数内 this 指向的不同场景

普通函数调用         window                        严格模式下是 undefined

构造函数调用        实例对象                      原型方法中 this 也是实例对象

对象方法调用        该方法所属对象           紧挨着的对象

事件绑定方法       绑定事件对象

定时器函数          window

函数也是对象

所有函数都是 Function 的实例

call:

call() 方法调用一个函数, 其具有一个指定的 this 值和分别地提供的参数(参数的列表)。

注意:该方法的作用和 apply() 方法类似,只有一个区别,就是 call() 方法接受的是若干个参数的列表,而 apply() 方法接受的是一个包含多个参数的数组。

apply

apply() 方法调用一个函数, 其具有一个指定的 this 值,以及作为一个数组(或类似数组的对象)提供的参数。

<p class="danger"> 注意:该方法的作用和 call() 方法类似,只有一个区别,就是 call() 方法接受的是若干个参数的列表,而 apply() 方法接受的是一个包含多个参数的数组。

bind

bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

总结

  •  call 和 apply 特性一样

    • 都是用来调用函数,而且是立即调用

    • 但是可以在调用函数的同时,通过第一个参数指定函数内部 this 的指向

    • call 调用的时候,参数必须以参数列表的形式进行传递,也就是以逗号分隔的方式依次传递即可

    • apply 调用的时候,参数必须是一个数组,然后在执行的时候,会将数组内部的元素一个一个拿出来,与形参一一对应进行传递

    • 如果第一个参数指定了 null 或者 undefined 则内部 this 指向 window

  • bind

    • 可以用来指定内部 this 的指向,然后生成一个改变了 this 指向的新的函数

    • 它和 call、apply 最大的区别是:bind 不会调用

    • bind 支持传递参数,它的传参方式比较特殊,一共有两个位置可以传递

        1. 在 bind 的同时,以参数列表的形式进行传递

        1. 在调用的时候,以参数列表的形式进行传递

      • 那到底以谁 bind 的时候传递的参数为准呢还是以调用的时候传递的参数为准

      • 两者合并:bind 的时候传递的参数和调用的时候传递的参数会合并到一起,传递到函数内部 

猜你喜欢

转载自blog.csdn.net/qq_43021088/article/details/82791024
今日推荐