库 vs 插件
库:一些基础的方法
插件:实现了独立功能的模块,如选项卡、日历等
封装的意义:复用、开箱即用

  • 🤔思考题:如何封装一个加减乘除四则运算库
  • jquery,$的符号是如何定义的

学习如何封装一个库

如何你看了jquery源码,就会熟悉这样的代码:

  1. ;(function(){
  2. //此处任性的省略n行代码
  3. window.$ = window.jQuery = jQuery
  4. })()

如上是一个匿名的自执行函数(闭包),在封装一个库的时候,有两点好处:
(1)解决命名冲突,防止变量污染
用一个匿名function包起来的代码形成一层作用域,外层代码是无法访问的

  1. ;(function(){
  2. var a = 8
  3. })()
  4. a//error a is not defined
  5. window.a //undefined
  6. //代码最前面的逗号是为了防止出现错误的,构成完整的代码块

(1.1)这里插播一个刚知道的知识点:
为何立即执行函数要写成这个样子:

  1. (function(){})()
  2. //or
  3. (function(){}())
  4. //or
  5. +function(){}()
  6. //or
  7. -function(){}()

为了是将函数声明转换为函数表达式,这样才能达到立即执行的效果。

(2)查找全局对象会比查找在私有作用域内的变量速度要慢,也就是我们经常说的,应该尽量用局部变量来代替全局变量,为何?
每个函数对象在创建的时候,都会生成一个叫做 [[Scope]]的内部属性这个内部属性包含创建函数时的作用域信息,函数在运行的时候,会访问到这个属性,引用阮一峰老师的一段代码,一张图:

class Student{
    int age;              
    String name;      

    public Student(int Age, String Name)
    {
        this.age = Age;
        setName(Name);
    }
    public void setName(String Name)
    {
        this.name = Name;
    }
}

public class Main{
    public static void main(String[] args) {
            Student s;           
            s = new Student(23,"Jonh");
    }
}

bg2013112902.gif

上面是一个调用栈,加工理解后的图:
scope.gif

如下的这些scope,构成来上下文的作用域链(Scope Chain),如果在当前scope没有找到该变量,则会沿着作用域链继续找,这个过程有点像原型链,
“总是先完成最上层的调用,然后将它的值返回到下一层调用,直至完成整个调用栈,返回最后的结果”。

查询标识符:可以将变量认为是标识符中的一种。

var color = 'blue'
function getColor(){
    return color
}
console.log(getColor())//blue
/*如果不用像上搜索作用域链,则会快的多,如果搜索到最后一层,都没找到,则返回undefined*/

scope2jpeg.jpeg

传入window缩小作用域的查找,提高性能(微乎极微,js引擎在优化标识符查询方面已经做的不错了)

;(function(global){
  var _global = (function(){return this || (0,eval)('this')})()
  var tool = {}
  !('tool' in global) && global.tool=tool

})(window)
//传入window参数仅对浏览器环境有效
/*
(0,eval)('this')获取当前上下文
这里用了逗号操作符,逗号操作符总会返回表达式中的最后一项,所以0在这里基本上没有什么用,换成其他任意数值均可
相当于执行了:eval('this')
*/

(3)模块化

;(function(global){
  var _global = (function(){return this || (0,eval)('this')})()
  var tool = {}

  //module
  if(typeof module!=='undefined' && module.exports && typeof exports === 'object'){
      //commonjs
    module.exports = tool
  }else if(typeof define ==='function' && define.amd ){
    //adm
    define(function(){
        return tool
    })
  }else {
      //设置顶层结构
    !('tool' in global) && global.tool=tool
  }

})(window)