原型/原型链/闭包立即执行函数/插件开发

73 阅读4分钟

1617003074757-e8ff1611-f167-434e-84bd-dafe122cd76a.png

📌 原型

任何对象都有一个原型对象,这个原型对象由内部属性 proto 指向它的构造函数的 prototype 指向的对象

任何对象都是由一个构造函数创建的,被创建的对象都可以获得构造函数的 prototype 属性

任何对象都有一个 constructo r 属性,指向创建此对象的构造函数


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

// 直接调用Person()就是一个普通函数
function Person() {}

// 只有通过new产生实例对象,这个函数才是new出来实例对象的构造函数
var p = new Person();

// 只有方法才有prototype属性,普通对象无prototype
console.log(Person.prototype); // Object{} 
console.log(p.prototype); // undifined
	
//任何对象都是有构造函数constructor,由构造函数创建的对象也可以获得构造函数的引用
//此处只是打印下列对象的构造函数是什么。
// 实例对象的constructor属性指向创建该实例对象的构造函数
console.log(p.constructor); //function Person(){}  

console.log(Person.constructor); //function Function(){} 

console.log({}.constructor); // function Object(){}

console.log(Object.constructor); // function Function() {}

console.log([].constructor);  //function Array(){}

// 只要是对象就是有构造函数来创建的
// 其内部的__proto__是从构造函数的prototype衍生的一个指向
// 而构造函数的prototype也是一个对象,那么它肯定也由一个构造函数创建
// 它是一个Object {} 对象,它的构造函数肯定是Object,所以就会有一个指针_proto_指向Object.prototype
// 最后Object.prototype因为没有_proto_,指向null,这样就构成了一个原型链

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

实例对象的__proto__和 构造函数的prototype 相等

实例对象的__proto属性指向了方法的prototype属性,且constructor指向了方法prototype的 constructor属性

📌 原型链

function Person(name){
     this.name = name;
 }
var p = new Person();
     
//p ---> Person.prototype --->Object.prototype---->null

// p的构造函数是Person创建的,那么Person.prototype就是继承的第一个原型
p.__proto__ === Person.prototype
// Person.prototype也是一个Object对象,即是Object构造函数创建的,那么就是继承了Object.prototype
Person.prototype.__proto__ === Object.prototype 
// Object.prototype再往上就没有__proto__指向了,等于null
Object.prototype.__proto__ === null

原型链核心

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

属性搜索原则原则:

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

📌 闭包立即执行函数

function test() {
  var a = 1;
  function plus(){
  	a++
    console.log(a)
  }
  return plus
}
var plus = test()
plus(); // 2
plus(); // 3
plus(); // 4
-----------------------------------------
function test() {
  var a = 1;
  function plus(){
  	a++
    console.log(a)
  }
  window.plus = plus
}
window.plus(); // 2
window.plus(); // 3
window.plus(); // 4

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

(function(){
    var meg = "hello zdx";  
    function say(arg){
       arg = arg || meg;
       console.log(arg)
    }
    window.say = say;
})(window)

window.say();  //"hello zdx"

函数中使用 windowreturn 的区别?

  • 相同点:

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

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

📌 插件的开发

立即执行函数,可以防止全局变量污染及函数作用域的污染

一般在立即函数内的构造函数中定义插件需要使用的参数

一般在立即函数内构造函数原型prototype上定义插件的方法

通过window将立即执行函数中的构造函数挂载到全局

全局中即可通过new关键字创建该构造函数的实例对象,从而可调用到该构造函数上的方法

;(function () {
 
  function Test(){
  }
  
  Test.prototype = {
  }
  
  window.Test = Test;
})();

var test = new Test()

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

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

📋 练习

> 1、写一个插件,任意传两个数字,调用插件内部方法可以进行加减乘除功能? >
;(function (){
   function Computed(opt){
     this.firstNum = opt.firstNum;
     this.secendNum = opt.secendNum;
   };
   Computed.prototype = {
     plus: function () {
       return this.firstNum + this.secendNum
     },
     minus: function () {
       return this.firstNum - this.secendNum
     },
     mul: function () {
       return this.firstNum * this.secendNum
     },
     div: function () {
       return this.firstNum / this.secendNum
     }
   }

   window.Computed = Computed
})()

var computed = new Computed({
   firstNum: 10,
   secendNum: 5
})

var plusRes =  computed.plus()
var minusRes =  computed.minus()
var mulRes =  computed.mul()
var divRes =  computed.div()
console.log(plusRes, minusRes, mulRes, divRes)