prototype5.png

📌 原型

任何对象都有一个原型对象,这个原型对象由内部属性**proto指向它的构造函数的prototype**指向的对象 任何对象都是由一个构造函数创建的,被创建的对象都可以获得构造函数的**prototype**属性 任何对象都有一个**constructor属性,指向创建此对象的构造函数**


注意 对象是没有prototype属性的,只有方法才有prototype属性**

  1. // 直接调用Person()就是一个普通函数
  2. function Person() {}
  3. // 只有通过new产生实例对象,这个函数才是new出来实例对象的构造函数
  4. var p = new Person();
  5. // 只有方法才有prototype属性,普通对象无prototype
  6. console.log(Person.prototype); // Object{}
  7. console.log(p.prototype); // undifined
  8. //任何对象都是有构造函数constructor,由构造函数创建的对象也可以获得构造函数的引用
  9. //此处只是打印下列对象的构造函数是什么。
  10. // 实例对象的constructor属性指向创建该实例对象的构造函数
  11. console.log(p.constructor); //function Person(){}
  12. console.log(Person.constructor); //function Function(){}
  13. console.log({}.constructor); // function Object(){}
  14. console.log(Object.constructor); // function Function() {}
  15. console.log([].constructor); //function Array(){}
  16. // 只要是对象就是有构造函数来创建的
  17. // 其内部的__proto__是从构造函数的prototype衍生的一个指向
  18. // 而构造函数的prototype也是一个对象,那么它肯定也由一个构造函数创建
  19. // 它是一个Object {} 对象,它的构造函数肯定是Object,所以就会有一个指针_proto_指向Object.prototype
  20. // 最后Object.prototype因为没有_proto_,指向null,这样就构成了一个原型链

通过 **new关键字** 创建的实例对象:

实例对象的proto和**构造函数的prototype相等 实例对象的__proto属性指向了方法的prototype属性,且constructor指向了方法prototype的**constructor属性

📌 原型链

  1. function Person(name){
  2. this.name = name;
  3. }
  4. var p = new Person();
  5. //p ---> Person.prototype --->Object.prototype---->null
  6. // p的构造函数是Person创建的,那么Person.prototype就是继承的第一个原型
  7. p.__proto__ === Person.prototype
  8. // Person.prototype也是一个Object对象,即是Object构造函数创建的,那么就是继承了Object.prototype
  9. Person.prototype.__proto__ === Object.prototype
  10. // Object.prototype再往上就没有__proto__指向了,等于null
  11. Object.prototype.__proto__ === null

原型链核心依赖于实例对象的proto指向,当自身不存在属性时,就一层层向上扒该实例对象的构造函数,直至顶级Object构造函数的prototype就没有proto指向了

**

属性搜索原则原则:

  • 当访问一个对象的成员的时候,会现在自身找有没有,如果找到直接使用
  • 如果没有找到,则去原型链指向的对象的构造函数的prototype中找,找到直接使用,没找到就返回undifined或报错

📌 闭包立即执行函数

  1. function test() {
  2. var a = 1;
  3. function plus(){
  4. a++
  5. console.log(a)
  6. }
  7. return plus
  8. }
  9. var plus = test()
  10. plus(); // 2
  11. plus(); // 3
  12. plus(); // 4
  13. -----------------------------------------
  14. function test() {
  15. var a = 1;
  16. function plus(){
  17. a++
  18. console.log(a)
  19. }
  20. window.plus = plus
  21. }
  22. window.plus(); // 2
  23. window.plus(); // 3
  24. window.plus(); // 4

立即执行函数配合闭包 实现模块化中应用

  1. (function(){
  2. var meg = "hello zdx";
  3. function say(arg){
  4. arg = arg || meg;
  5. console.log(arg)
  6. }
  7. window.say = say;
  8. })(window)
  9. window.say(); //"hello zdx"

函数中使用** windowreturn 的区别?**

  • 相同点:

都是将其内部的值暴露给全局,以便全局进行调用

  • 不同点:
    • return 需要一个全局变量接收函数执行后的返回值,在全局使用全局变量
    • window 在函数内部直接将值保存到window的自定义属性上,全局使用即可

**

📌 插件的开发

立即执行函数,可以防止全局变量污染及函数作用域的污染 一般在立即函数内的构造函数中定义插件需要使用的参数 一般在立即函数内构造函数原型prototype上定义插件的方法 通过window将立即执行函数中的构造函数挂载到全局 全局中即可通过new关键字创建该构造函数的实例对象,从而可调用到该构造函数上的方法

  1. ;(function () {
  2. function Test(){
  3. }
  4. Test.prototype = {
  5. }
  6. window.Test = Test;
  7. })();
  8. var test = new Test()

关于立即执行函数前 ;分号的原因:

  • 一般分号 墨守成规 在写立即函数时,先写 ;分号
  • 在代码压缩时不会出现错误


    📋 课后作业

    1、写一个插件,任意传两个数字,调用插件内部方法可以进行加减乘除功能?

  1. ;(function (){
  2. function Computed(opt){
  3. this.firstNum = opt.firstNum;
  4. this.secendNum = opt.secendNum;
  5. };
  6. Computed.prototype = {
  7. plus: function () {
  8. return this.firstNum + this.secendNum
  9. },
  10. minus: function () {
  11. return this.firstNum - this.secendNum
  12. },
  13. mul: function () {
  14. return this.firstNum * this.secendNum
  15. },
  16. div: function () {
  17. return this.firstNum / this.secendNum
  18. }
  19. }
  20. window.Computed = Computed
  21. })()
  22. var computed = new Computed({
  23. firstNum: 10,
  24. secendNum: 5
  25. })
  26. var plusRes = computed.plus()
  27. var minusRes = computed.minus()
  28. var mulRes = computed.mul()
  29. var divRes = computed.div()
  30. console.log(plusRes, minusRes, mulRes, divRes)