Morry's Blog

A wizzard is never late.

Flask-Peewee

    发现自己这段时间越来越浮躁起来,总是赶着时间完成项目,好久没有安静下来研究一些什么东西了。一本小说都看了一个月才看完,第一张不知道拿起放下看了多少遍,趁着坐火车的时间才看了下来,更别说画画了。前几天接到校友会组织创业大赛的一个网站,顺便要帮忙写个后台,因为正好室友实验室课题组要建个主页,也要做个简单的发布系统让她后续好简单点发布。想想功能也简单,就想顺手用最熟悉的框架flask做了吧,虽然知道用flask来作这种东西真是有点作死的节奏。写的时候就觉得跟当时学flask时候的心境真的相差太多,真是特别怀念当年天天泡图书馆的日子。也发现了现在人的审美也慢慢提高,对设计和体验也越来越在乎,好看的网站越来越多,所以很多早几年拿wordpress或者直接拖模版的网页已经让人越来越不能忍了。正好赶上了网页换代的好时代,这样简单的活光在校内的需求都这么大,就想自己顺便琢磨琢磨把整个系统完善一下,尽量以后可以多复用一点。

    先总结一下最近研究下来几个插件:

  1. CKEditor
  2. Flask-Admin(虽然最后没有用成功)
  3. Flask-Peewee

本来是打算用熟悉点的SQLAlchemy+Admin直接做后台操作的,但是因为Admin的templates实在无法override(也不知道问题到底出在哪了,以后再研究一下),碰巧发现了peewee,真是很轻量级又很赞的组合,直接用peewee-orm可以做好数据库,后来发现用的居然就是SQLAlchemy的内核,不过api感觉简单好用更多。后台操作的用法和Flask-Admin基本差不多,最重要的是example的代表性很好,对flask项目的模块管理又重新学习了一下。

作为一个前端,当然最重要的还是对CKEditor的学习啦,在这里还是赞一下CKEditor4的改版ui,真是很清新。上手很快,基本就是把存成在html格式放在数据库里,提取信息的问题上花时间搜索的有点多,结果居然在django的讨论帖上发现直接autoescaping off就行了。可能django和flask用的html渲染差不多都是jinja,所以也比较通用。后来查了一下应该也是可以直接通过js的方法来反转义的,就是一些标签的转义而已。还有没解决好的问题就是图片上传和浏览的问题,可能还得用上ckfinder,过几天也得好好研究一下源码。

代码库直接挂在github-zaec上了,学长说交东西不要太快,最好等deadline前几天再给人家,不然老是会被要求修改的(哈哈,真是太机智了)。等过几天,再慢慢把这个系统完善一下,尽量做成一个简单的cms。

Javascript Function

It took me days to really understand what a closure is in javascript, and finally I have grokked the core concept. And here are some share to whom is new to the language like me. And this article is for some basic concepts about javascript functions, which is very important when learning the closure.

It is a little hard to get the concept by the definition. I have been reading articles and books these days to understand how javascript function works, which seems so different from other languages like C, Python, etc. The more you get, the more confused you are, as people have really different understandings. Some of them are confusing, and some of them are misunderstanding or even wrong, as everyone makes mistakes. And finally I come to the idea that the best way to learn it is typing the code to you browser and debug to see how it works. It really helps alot. Let me explore it a little bit deeper by the examples.

We first started by some basic concept about javascript function:

Definition

There are 3 ways to define a function in javascript:

  1. function funcname(para1, para2){ … }
  2. var funcname = function(para1, para2){ … }
  3. var funcname = Function(para1, para2, “…”);

By using the first one, you are creating a function with a name funcname, which is actually a pointer to the function. It is called function declaration. By using the second two, you are creating a function which is widely know as a anonymous function. It is called a function expression, which returns a pointer, and you can assign it to a variable funcname so as to call(invoke) it. The diffrence between them is how the browser loads them into the execution context:

function declarations loads before any code is executed.

While function expressions loads only when the interpreter reaches that line of code.

By declaring a function, you can call it before you have actually defined. That is because javascript has the mechanisim to raise the function decalration before any code is excuted, while you cannot do that in the second situation.

Invocation

The invocation is really different from a difinition, especially in these scrtipt language. A function is never executed until it is invoked. As metioned in Javascript: The Good Parts, there are 4 paterns of invovation in javascript:

  1. The Method Invocation Pattern
  2. The Function Invocation Pattern
  3. The Constructor Invocation Pattern
  4. The Apply Invocation Pattern

The difference between them is how the special varible this is initialized.

The method invocation pattern

If an invocation expression con- tains a refinement (that is, a . dot expression or [subscript] expression), it is invoked as a method. A common patern is like:

var num = Myobject.method(para1, para2);

In this way, the bonus parameter this is bound to the object Myobject. That is when you alert(this) inside the function, it will alert Object Myobject.

The function invocation pattern

When a function is not the property of an object, then it is invoked as a function:

 var sum = add(3, 4);    // sum is 7

Most of the function are invoked in this way. In this case, the bonus parameter this is bound to the global object. That is when you alert(this) inside the function, it will alert Object Global(or mostly the Window object in a browser).

The constructor invocation pattern

If a function is invoked with the new prefix, then a new object will be created with a hidden link to the value of the function’s prototype member, and this will be bound to that new object. That is what confused me at the first glance, about how a constructor works in javascript which is made by a function without a class being defined. The author gave a clear answer that javascript is a prototypal inheritance language while offers an object-making syntax that is reminiscent of the classical languages.

The apply invocation pattern

The apply method lets us construct an array of arguments to use to invoke a func- tion. It also lets us choose the value of this. The apply method takes two parame- ters. The first is the value that should be bound to this. The second is an array of parameters. To identify the differences, I will go to an overall example:Firstly, define an object:

function Person(){  };

It is just used to demonstrate the object machanism, so we actually have nothing in it.

Secondly, create an instance called p of object Person

var p = new Person();

Thirdly, create a method displayneme by assigning it a function:

p.displayname=function(){

    alert(this); //object p

    return function dis(){ 
        alert(this);  //window
    }
}
var disp = p.displayname();  //get the pointer of the function
disp();   //invoke it

If we rearrange the order of the code to:

    var p = new Person();
    var disp = p.displayname();  //get the definition of the function
    disp();   //invoke it, error occurs
    p.displayname=function(){

        alert(this); 

        return function dis(){ 
            alert(this);  
        }
    }
    function Person(){
    }

It will alert an error that Person has no method displayname, but we can still create the p instance before we define an object Person. That is because the constructor function isn raised before the code is executed, while the function p.displayname is loaded when the interpreter reaches that line.

If we look at how the alert box shows us the this parameter, we can easily know that the inside the first function, p.displayname, this = object p, while in the second function, dis(), this = global object window. The second function, which is invoked in a function patern, it just doesn’t have the access to the object p.

Another way to invoke that inner function is:

p.displayname=function(){

    alert(this); //object p

    return function dis(){ 
        alert(this);  //window
    }();   // invoke directly
}
p.displayname();  //get the pointer of the function

The function about is called a self-invoking function, by adding a () after the definition of the function. In this way, we don’t need to assign the inner function to a variable disp to invoke it, and get the result in the inner function.

CSS Crossbrowser Compatibility

CSS Hacks:

Techniques and syntax that achieve desired results by exploiting a bug in a particular browsers rendering engine.

CSS Filters:

Techniques and syntax that achieve desired results by exploiting a feature that a particular browsers rendering engine does not yet support.

How CSS Visual Formatting Model Works

It is a common sense that:

the width of a box = width + margin-left + margin-right + padding-left + padding-right + border-left + border-right (rule 1)

based on the box model in CSS. However, there is one more thing to add:

the default width of a block-level element always = the width of its parent element (rule 2)

until a width is set. Setting width makes a structure less flexible, especially when it refers to a px unit. Let’s go to a simple example, we have such html code bellow:

<div>
    <p>blabla</p>
</div>

with a css style:

 div{
     border: solid 1px black;
 }
 p{
     border: solid 1px black;
 }

As expected, the result shows as following:

block

Here we have a clear html structure: html->div->p, which are all block-level elements. As initialed, the html element has a 100% width of the window by default, thus, the child element div got the same width as his parent, width:100%, and so does the child p element applied rule 2 above. If the width is set by an author:

 div{
     border: solid 1px black;
     width:100px; /* the width is set */
 }
 p{
     border: solid 1px black;
 }

The whole visual formatting changed as bellow:

block

However, a width definition of a child element has no effect on its parent, it doesn’t have the control:

 div{
     border: solid 1px black;         
 }
 p{
     border: solid 1px black;
     width:100px; /* the width is set */
 }

Result:

block

You can change the width of the box of the p element by assigning a padding or margin value to it:

 div{
     border: solid 1px black;         
 }
 p{
     border: solid 1px black;
     width:100px; /* the width is set */
     padding:100px; /* the padding is set */
 }

By using the power of padding, the redundant div tag could be removed, if your goal is to creating a box like this:

The whitespace of the border and the centered form could be made simply by using a padding instead of alot of sizing and centering work.

Here, another way of determining the size of an element is called Block Formatting Context(BFC) mentioned in CSS Mastery which is often used for the height collapse problem of the blocks with floated children. Conversely, the mechanism goes the posite way from the nomal formatting. When an element is triggered with the BFC, it is responsible for sizing and positioning itself and its children. It common with the widely known hasLayout feature in IE browser. That means it decides it size(width and height) and position based on its children instead od its parent. We can see it from the height collapse problem, suppose we have a list:

<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

and style sheet:

ul{
    border: solid 1px red;
    text-align:center;
    vertical-align:baseline;
    list-style: none;
}


li{
    border: solid 1px black;
    float:left;
    margin:100px;
}

Result: block

we mark the border of ul as red so that to identify the parent element, we can see that the height is collapsed. Why does this happen?

While the width of an element is determined by its parent’s width, the height of it is enclosed by its children, with a prerequisite that the children are in the normal flow. Setting an element a float style(this happen in absolute positioning as well) takes it out of the normal flow-positioning model, while the parent element is still in the flow. The parent cannot find any children in its normal flow model, thus the height gose to zero when enclosing the box, like how you see in the pic above.

A popular solution to this problem is setting an overflow:hidden style to the perent. And that is where Block Formatting Context is triggered. As we mentioned:

When an element is triggered with the BFC, it is responsible for sizing and positioning itself and its children.

The word responsible explicates how the BFC works: it is forsed to cauculate the height based on its children’s height no matter if they are in normal-positioning flow or not. A block formatting context is created by one of the following:

  • float other than none
  • position fixed or absolute
  • display inline block
  • table cells (elements with display: table-cell, which is the default for HTML table cells)
  • table captions (elements with display: table-caption, which is the default for HTML table captions)
  • overflow other than visible
  • flex boxes (elements with display: flex or inline-flex)

Notice here the trigger is about the parent, that means, the float, absolute psition, or overflow:hidden is set to the parent, we can see the results:

By set overflow: hidden: block By set float: left or position: absolute: block

Summary

Those are almost the main machenisms of the Visual Formatting Model in CSS. And here are the three formatting models in CSS: normal flow, absolute positioning, and floating. We can figure out the first one by rule 1 and rule 2 in the artucle, while the last two is a little more complicated to figure by the Block Formatting Context. There are always multiple solutions when dealing withe css problems, it is a good way to practice and learn from the cases.

He Is Going to Princeton

Yes, still cannot help missing him.

It’s been almost 7 years, since we first met. You sat there still at the back of the room, looking at me. Silence, and heart beating so loudly. I thought I must have met you before, but actually not. Being a classmate of you, I didn’t talk to you except the first days when you kept asking my name. Feeling so sorrow to be forgotten, we were just too young to love.

The real story began about 5 years ago. It was a hard time with the endless homework for a third-year high school student in China. The only common thing among us could be that we are both boarders, and good at physics in a way. You started to talk with me, asked me questions, glared at me when I was talking to other boy, playing with my pens, looked at me when I was called by the teacher for questions like a real couple, but actually we were not. Those sweet days were kept in my whole life, I thought I was flipped, completely. I swear I loved you more than any boyfriend I have ever dated.

Not all stories get a happy ending. It ends up with my stupid stubbornness and pride. I know it’s hard to restart, but I will try. Before that, I still want to improve myself so that to talk to you without my inferiority the next time I see you. As you deserve a better girl. Life is long, it’s never too late to chatch. Focus on my next 3 years, and hope it sparks!

Congratulations!

Sincerely,

yours,
forever admirer.

How to Use CSS More Efficiently

    It all starts from a question on stackoverflow. I have been working on the website weixinfr these days, as we haven’t decided the main color style yet, it troubles me repeatedly changing from color to color. For instance, I use red as the color of active link, some titles, the background color of buttons and some selectors. But what if I want to change the color style to green next time? Should I find all the “red”(or #whatever) keyword in the text and determine on each fragment if it is the one to change?

    Color, font, positioning are the main functions of css, I used to define all of them on a certeain box, like:

for box1:

#nav-wrapper{
    position:fixed;  //positioning
    height: 60px;
    z-index: 60;
    width: 100%;
    padding: 0;
    margin:0;
    text-align: center;   //for text
    background-color: #fff;    //bg-color
    color: red;
    border-bottom: solid 1px #ececec;     //color
}

for box2, repeatedly:

#login-form{
    text-align: left;
    color: white;
    position: absolute;
    top: 70px;
    right: 80px; 
    z-index: 80;
    display: block;
    background-color: rgba(0,0,0,0.4); 
    padding: 20px 35px;
}

so everytime I am going to change, I have to check every box to change the color. The idea comes into my mind that how can I use a variable to store the number of the color, and put it somewhere I use it? I know something like less makes it possible, but I also want some css solutions. Some anwsers on stackoverflow really inspires me. Colour reference chart, CSS3 variables, sass/scss, grouping the selectors only on color, and setting up a .red class Actually, I suppose the idea of the last two are the same: always group up the common style/feature togeter. One of the most exciting things in css is each element can have more than one class. To compare with the 2 solutions, we can still find some differences though. By defining a class called “red_text”, I am forced to guess to which element that class could refer to remove or add the class, and things are already starting to get confusing. And once I want to change the color to green, I have to rename it “green_text” for the readability, and do the find-replace routine to update the whole html file.

.red{color:red;}

The new problem is mentioned in the book <CSS Mastery>:

It makes sense to name your elements based on what they are rather than how they look. That way your code will have more meaning and never go out of sync with your designs.

He also gives a pic for the recommanded names as below:

Alternatively, the second one makes it a little better, it only deals with the css file. But the trouble is you need to be careful about the selectors and probably generate a long chaind of ID selectors like:

#section1, #section2, #section3, #section4 {color:red;}

It is caused by the unstructual code like how I used to add classes/ids to nearly everything in an attempt to get fine-grained control over the styles. The debates between Id and Class is also a problem we encountered when styling. With the overreliance on id or class names, we will run out of unique names very quickly and end up creating extremely long and complicated naming conventions. A combined solution is given by the author, create a generic class for them all.

To conclude, a good choice is to name the elements based on what they are, like popout/highlight, warning, etc, and group up common features in a class, like combine foot_nav, top_nav, aside_nav to nav and use ID to identify something extremely specific. And group up the classes, elements, IDs in common feature into a style instaed of assigning them seperately.

.popout, h1, .warning {color:red}

There is no right answer, it all defers from the authors and the circumstances. New techs will lead up a new generation, gives new solutions. Let me end up with the quote of CSS Mastery:

Although the goal is to keep your code as lean and mean(ingful) as possible, sometimes you cannot avoid adding an extra nonsemantic div or span to get the page to display the way you want. If this is the case, don’t fret too much over it. We live in a transitional period, and CSS 3 will give us much greater control of our documents. In the meantime, real-world needs often have to come before theory. The trick is knowing when you have to make a compromise and if you are doing it for the right reasons.

Octopress Journey

    After one-day searching, I finally set up my own blog by octopress. It looks so amazing and I just fall in love with the green markdown at the first glance. I will just imigrate the previous blog http://www.cnblogs.com/sparkmorry/ @cnblog here.

    This is just a testing post where I learn how to write an article with markdown and post it under a certain page. According to the documentation of Octopress, to write a new post and create a new page:

rake new_page[super-awesome]
# creates /source/super-awesome/index.markdown

rake new_page[super-awesome/page.html]
# creates /source/super-awesome/page.html

to publish:

rake generate   # Generates posts and pages into the public directory
rake watch      # Watches source/ and sass/ for changes and regenerates
rake preview    # Watches, and mounts a webserver at http://localhost:4000
rake deploy
rake gen_deploy #combination

    I have come across a problem of the blog configuration, the source code should be under the root directory for preview, or maybe by changing somewhere else. I am still in my process of learning this new awsome tool.

    Here in my blog, the posts are under Articles. The articles are mainly about the reflections on front-end development and my daily life. Also, you may see some recent work on drawings or photographies under Gallery as I really like both of them. For more infomation, plz see About page. Thanks to github and octopress that I can set up the blog for free.

     If you have any issues or questions on the code or posts, please contact me. Lastly, I’m so pleasant of having your visit on this blog.

曲线参数化的Javascript实现(代码篇)

在曲线参数化的Javascript实现(理论篇)中推出了曲线弧长积分的公式,以及用二分法通过弧长s来查找样条曲线上对应的u,再求Q(u)的值。弧长积分函数如下:

,其中-----公式1

Simpson展开后

-------公式2

这里的f(u)就是上面的弧长s的求值函数,既样条曲线拟合函数Q(u)的积分

这部分具体代码如下:1.计算f(u)的系数ABCDE

CParametric.prototype.SegCoef = function(CSpline, o)
{        
    p0.x=this.k[0]*CSpline.Spline[o].x+this.k[1]*CSpline.Spline[o+1].x+this.k[2]*CSpline.Spline[o+2].x+this.k[3]*CSpline.Spline[o+3].x;
    p1.x=this.k[4]*CSpline.Spline[o].x+this.k[5]*CSpline.Spline[o+1].x+this.k[6]*CSpline.Spline[o+2].x+this.k[7]*CSpline.Spline[o+3].x;
    p2.x=this.k[8]*CSpline.Spline[o].x+this.k[9]*CSpline.Spline[o+1].x+this.k[10]*CSpline.Spline[o+2].x+this.k[11]*CSpline.Spline[o+3].x;
    p3.x=this.k[12]*CSpline.Spline[o].x+this.k[13]*CSpline.Spline[o+1].x+this.k[14]*CSpline.Spline[o+2].x+this.k[15]*CSpline.Spline[o+3].x;

    p0.y=this.k[0]*CSpline.Spline[o].y+this.k[1]*CSpline.Spline[o+1].y+this.k[2]*CSpline.Spline[o+2].y+this.k[3]*CSpline.Spline[o+3].y;
    p1.y=this.k[4]*CSpline.Spline[o].y+this.k[5]*CSpline.Spline[o+1].y+this.k[6]*CSpline.Spline[o+2].y+this.k[7]*CSpline.Spline[o+3].y;
    p2.y=this.k[8]*CSpline.Spline[o].y+this.k[9]*CSpline.Spline[o+1].y+this.k[10]*CSpline.Spline[o+2].y+this.k[11]*CSpline.Spline[o+3].y;
    p3.y=this.k[12]*CSpline.Spline[o].y+this.k[13]*CSpline.Spline[o+1].y+this.k[14]*CSpline.Spline[o+2].y+this.k[15]*CSpline.Spline[o+3].y;

    this.A=9*(p0.x*p0.x+p0.y*p0.y);
    this.B=12*(p0.x*p1.x+p0.y*p1.y);
    this.C=6*(p0.x*p2.x+p0.y*p2.y)+4*(p1.x*p1.x+p1.y*p1.y);
    this.D=4*(p1.x*p2.x+p1.y*p2.y);
    this.E=p2.x*p2.x+p2.y*p2.y;
}

这里的k数组是Cardinal样条曲线的Mc矩阵,具体内容可以参考Cardinal样条曲线的Javascript实现(理论篇)。这里的p0,p1,p2,p3就是公式1里的ax,ay,bx,by,cx,cy,dx,dy。从而求得积分函数系数。

2.计算扩展的Simpson方法展开后得到的积分函数

CParametric.prototype.ArcLength = function(ustart, uend){
    var h,sum,u;
    var i;
    h=(uend-ustart)*1.0/ITERATION_COUNT; //扩展的Simposon方法的阶数
    sum=0;
    u=ustart+h;

    for(var i=2; i <= ITERATION_COUNT; i++){
        if(!(i&1)){
            sum += 4.0*this.ArcIntergrand(u);
        }
        else{
            sum += 2.0*this.ArcIntergrand(u);
        }
        u += h;
    }
    return(h*this.ArcIntergrand(ustart)+sum+this.ArcIntergrand(uend)/3.0);
}

这里的ITERATION_COUNT是扩展的Simposon方法的阶数,既公式2中的n,其中的ArcIntergrand(u)就是求fi的值,代码如下:

CParametric.prototype.ArcIntergrand = function(u)
{
    var f;
    f=this.A*u*u*u*u+this.B*u*u*u+this.C*u*u+this.D*u+this.E;
    f=Math.sqrt(f);
    return f;
}

3.建立s-u索引表

上面的积分函数只能得到没一个曲线段上一个u对应s的值,而一整条样条曲线由多个小曲线段组成,比如计算第二段曲线上累加的s的值的时候只要把前面那段曲线的总长作为一个基数加上去就可以了。建立了s-u索引表之后就可以用二分法来查找每个给定的s对应的u的值了。因为这个函数是严格单调递增的,所以这个索引表肯定是升序的,就可以用二分法来查找。具体代码如下:

CParametric.prototype.SetLengths = function(spline, npoints){
    var no_segments;    //u分割的精度
    var arcLength;
    this.seg_lengths = new Array();

    no_segments = npoints-3;
    arcLength = 0;

    this.seg_lengths[0]=0;
    for(var i=0; i<no_segments; i++){
        this.SegCoef(spline, i);
        arcLength += this.ArcLength(0.,1.);   //ArcLength(0,1)就是前面一个曲线段的总长
        this.seg_lengths[i+1] = arcLength;
    }
    this.total_length = arcLength;
    for(var i=1; i<no_segments; i++){
        this.seg_lengths[i] /= this.total_length;  //s归一化
    }
}

因为弧长累加的值较大,所以对其进行归一化之后可以得到更标准的弧长值。

4.二分法计算弧长为seg的曲线上的点的位置pt

CParametric.prototype.ArcLengthPoint = function(spline, seg){
    var uL=0., uR=1., usearch;
    var segment_dist, ssearch;
    var segment_no=0;

    do{
        segment_no++;
    }while(this.seg_lengths[segment_no] < seg);
    segment_no --;
    segment_dist = this.total_length*(s-this.seg_lengths[segment_no]);

    this.SegCoef(spline,segment_no);

    do{
        usearch = (uL+uR)/2;
        ssearch = this.ArcLength(uL, usearch);

        if(segment_dist < ssearch+SEARCH_TOL){
            uR=usearch;
        }
        else{
            uL=usearch;
            segment_dist -= ssearch;
        }
    }while((segment_dist>ssearch+SEARCH_TOL) || (segment_dist<ssearch-SEARCH_TOL));
    this.GetPointOnSpline(usearch);

};

就是普通的二分查找法,给定一个弧长seg,在函数曲线上找到对应的u的值,返回的usearch就是在指定精度var SEARCH_TOL=0.5(可以任意指定)的情况下得到的u的值。再通过调用this.GetPointOnSpline(usearch)函数来计算u=usearch时对应的Q(u)的值。

CParametric.prototype.GetPointOnSpline=function(usearch){
    this.pt[pointnum]= new CPT();
    this.pt[pointnum].x=p0.x*usearch*usearch*usearch+p1.x*usearch*usearch+p2.x*usearch+p3.x;
    this.pt[pointnum].y=p0.y*usearch*usearch*usearch+p1.y*usearch*usearch+p2.y*usearch+p3.y;
}

Self-invoking Function in Javascript

在看bootstrap的轮播插件源码的时候发现一种新的自调函数的写法(其实应该不新了),开头的一段就卡住了,原谅我是个菜鸟,就顺便记录一下。stackoverflow上有大神们的回答在这里,轮播的函数形式如下:

!function ($) {
   //code here
}(window.jQuery);

通常自调函数来模仿块级作用域的方式是:

(function(parameters){
     //这里是块级作用域
})();

在function外面的这对括号使里面的匿名函数变成了函数表达式,并在之后马上调用。这个相当于:

var Name=function(parameters){
   //这里是块级作用域
}; 
Name();  //调用匿名函数

函数表达式是在运行中以引用的方式赋值给一个变量的,如上面的函数创建的方式。而这里函数表达式和函数声明是不一样的,函数声明的通常形式如下:

function Name(parameters){
    //code here
}

函数声明会在程序刚开始运行的时候会被提升(所以可以在执行之后声明),但是并不执行,直到被调用的时候再执行。

所以与括号作用相同的function前面的感叹号,因为括号的优先级高于感叹号,感叹号使得后面的一整串内容变成了一个bool表达式,编译器就会直接运行这个表达式了。这个表达式是个匿名函数,传入了一个参数,这里命名成$,其实无所谓是什么,只是一个形参,并在自调的时候把jQuery对象传进去,这里的jQuery对象是个全局变量,所以是windows.jQuery