还可以使用Object.create()来进行,因为之前接手的

2019-08-31 作者:小鱼儿主页高手论坛   |   浏览(176)

jQuery中:first选择器用法实例,jquery选择器

本文实例讲述了jQuery中first选择器用法。分享给大家供大家参考。具体分析如下:

此选择器匹配指定元素集合中的第一个元素。

语法结构:

复制代码 代码如下:

$(":first")

在使用中一般要和其他选择器配合使用,比如类选择器和元素选择器等等。例如:

复制代码 代码如下:

$("li:first").css("color","green")

以上代码能够将li元素集合中的第一个li元素中的字体颜色设置为绿色。
如果不和其他选择器配合使用,则默认状态是和*选择器配合使用,例如$(":first")等同于$("*:first")。

实例代码:

实例一:

复制代码 代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="" />
<title>帮客之家</title>
<script type="text/javascript" src="mytest/jQuery/jquery-1.8.3.js"></script>
<script type="text/javascript">
$(document).ready(function(){
  $("button").click(function(){
    $("li:first").css("color","green")
  })
})
</script>
</head>
<body>
<div>
  <ul>
    <li class="zhuanqu">html专区</li>
    <li class="zhuanqu">div css专区</li>
    <li class="zhuanqu">jQuery专区</li>
    <li class="zhuanqu">Javascript专区</li>
  </ul>
</div>
<button>点击查看效果</button>
</body>
</html>

以上代码能够将li元素集合中的第一个li元素中的字体颜色设置为绿色。

实例二:

复制代码 代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset=" utf-8">
<meta name="author" content="" />
<title>帮客之家</title>
<script type="text/javascript" src="mytest/jQuery/jquery-1.8.3.js"></script>
<script type="text/javascript">
$(document).ready(function(){
  $("button").click(function(){
    $(":first").css("color","green")
  })
})
</script>
</head>
<body>
<div>
  <ul>
    <li class="zhuanqu">html专区</li>
    <li class="zhuanqu">div css专区</li>
    <li class="zhuanqu">jQuery专区</li>
    <li class="zhuanqu">Javascript专区</li>
  </ul>
  <div>
    <span>帮客之家</span>
    <span>太阳出来了</span>
  </div>
</div>
<button>点击查看效果</button>
</body>
</html>

以上代码由于没有指定与:first选择器匹配的选择器,那么默认将会和*选择器配合使用,所以上面的代码将会将所有元素中的字体颜色设置为绿色。

希望本文所述对大家的jQuery程序设计有所帮助。

本文实例讲述了jQuery中first选择器用法。分享给大家供大家参考。具体分析如下: 此选择器匹配指...

Mustache.js前端模板引擎源码解读

mustache是一个很轻的前端模板引擎,因为之前接手的项目用了这个模板引擎,自己就也继续用了一会觉得还不错,最近项目相对没那么忙,于是就抽了点时间看了一下这个的源码。源码很少,也就只有六百多行,所以比较容易阅读。做前端的话,还是要多看优秀源码,这个模板引擎的知名度还算挺高,所以其源码也肯定有值得一读的地方。

 

  本人前端小菜,写这篇博文纯属自己记录一下以便做备忘,同时也想分享一下,希望对园友有帮助。若解读中有不当之处,还望指出。

 

  如果没用过这个模板引擎,建议 去 试着用一下,上手很容易。

 

  摘取部分官方demo代码(当然还有其他基本的list遍历输出): 

 

 

数据:

{

  "name": {

    "first": "Michael",

    "last": "Jackson"

  },

  "age": "RIP"

}

 

模板写法:

* {{name.first}} {{name.last}}

* {{age}}

 

渲染效果:

* Michael Jackson

* RIP

 

  OK,那就开始来解读它的源码吧:

 

  首先先看下源码中的前面多行代码:

 

 

var Object_toString = Object.prototype.toString;

    var isArray = Array.isArray || function (object) {

            return Object_toString.call(object) === '[object Array]';

        };

 

    function isFunction(object) {

        return typeof object === 'function';

    }

 

    function escapeRegExp(string) {

        return string.replace(/[-[]{}()* ?.,\^$|#s]/g, "\$&");

    }

 

    // Workaround for

    // See

    var RegExp_test = RegExp.prototype.test;

    function testRegExp(re, string) {

        return RegExp_test.call(re, string);

    }

 

    var nonSpaceRe = /S/;

    function isWhitespace(string) {

        return !testRegExp(nonSpaceRe, string);

    }

 

    var entityMap = {

        "&": "&",

        "<": "<",

        ">": ">",

        '"': '"',

        "'": ''',

        "/": '/'

    };

 

    function escapeHtml(string) {

        return String(string).replace(/[&<>"'/]/g, function (s) {

            return entityMap[s];

        });

    }

 

    var whiteRe = /s*/;    //匹配0个或以上空格

    var spaceRe = /s /;    //匹配一个或以上空格

    var equalsRe = /s*=/;  //匹配0个或者以上空格再加等于号

    var curlyRe = /s*}/;  //匹配0个或者以上空格再加}符号

 

  这些都比较简单,都是一些为后面主函数准备的工具函数,包括

 

  · toString和test函数的简易封装

 

  · 判断对象类型的方法

 

  · 字符过滤正则表达式关键符号的方法

 

  · 判断字符为空的方法

 

  · 转义字符映射表 和 通过映射表将html转码成非html的方法

 

  · 一些简单的正则。

 

  一般来说mustache在js中的使用方法都是如下:

 

var template = $('#template').html();

  Mustache.parse(template);   // optional, speeds up future uses

  var rendered = Mustache.render(template, {name: "Luke"});

  $('#target').html(rendered);

   所以,我们接下来就看下parse的实现代码,我们在源码里搜索parse,于是找到这一段

 

mustache.parse = function (template, tags) {

        return defaultWriter.parse(template, tags);

    };

  再通过找defaultWriter的原型Writer类后,很容易就可以找到该方法的核心所在,就是parseTemplate方法,这是一个解析器,不过在看这个方法之前,还得先看一个类:Scanner,顾名思义,就是扫描器,源码如下

 

 

/**

     * 简单的字符串扫描器,用于扫描获取模板中的模板标签

     */

    function Scanner(string) {

        this.string = string;   //模板总字符串

        this.tail = string;     //模板剩余待扫描字符串

        this.pos = 0;   //扫描索引,即表示当前扫描到第几个字符串

    }

 

    /**

     * 如果模板被扫描完则返回true,否则返回false

     */

    Scanner.prototype.eos = function () {

        return this.tail === "";

    };

 

    /**

     * 扫描的下一批的字符串是否匹配re正则,如果不匹配或者match的index不为0;

     * 即例如:在"abc{{"中扫描{{结果能获取到匹配,但是index为4,所以返回"";如果在"{{abc"中扫描{{能获取到匹配,此时index为0,即返回{{,同时更新扫描索引

     */

    Scanner.prototype.scan = function (re) {

        var match = this.tail.match(re);

 

        if (!match || match.index !== 0)

            return '';

 

        var string = match[0];

 

        this.tail = this.tail.substring(string.length);

        this.pos = string.length;

 

        return string;

    };

 

    /**

     * 扫描到符合re正则匹配的字符串为止,将匹配之前的字符串返回,扫描索引设为扫描到的位置

     */

    Scanner.prototype.scanUntil = function (re) {

        var index = this.tail.search(re), match;

 

        switch (index) {

            case -1:

                match = this.tail;

                this.tail = "";

                break;

            case 0:

                match = "";

                break;

            default:

                match = this.tail.substring(0, index);

                this.tail = this.tail.substring(index);

        }

 

        this.pos = match.length;

        return match;

    };

 

  扫描器,就是用来扫描字符串,在mustache用于扫描模板代码中的模板标签。扫描器中就三个方法:

 

  eos:判断当前扫描剩余字符串是否为空,也就是用于判断是否扫描完了

 

  scan:仅扫描当前扫描索引的下一堆匹配正则的字符串,同时更新扫描索引,注释里我也举了个例子

 

  scanUntil:扫描到匹配正则为止,同时更新扫描索引

 

  看完扫描器,我们再回归一下,去看一下解析器parseTemplate方法,模板的标记标签默认为"{{}}",虽然也可以自己改成其他,不过为了统一,所以下文解读的时候都默认为{{}}:

 

 

    function parseTemplate(template, tags) {

        if (!template)

            return [];

 

        var sections = [];     // 用于临时保存解析后的模板标签对象

        var tokens = [];       // 保存所有解析后的对象

        var spaces = [];       // 保存空格对象在tokens里的索引

        var hasTag = false;    

        var nonSpace = false;  

 

 

        // 去除保存在tokens里的空格标记

        function stripSpace() {

            if (hasTag && !nonSpace) {

                while (spaces.length)

                    delete tokens[spaces.pop()];

            } else {

                spaces = [];

            }

 

            hasTag = false;

            nonSpace = false;

        }

 

        var openingTagRe, closingTagRe, closingCurlyRe;

 

        //将tag转成正则,默认的tag为{{和}},所以转成匹配{{的正则,和匹配}}的正则,已经匹配}}}的正则(因为mustache的解析中如果是{{{}}}里的内容则被解析为html代码)

        function compileTags(tags) {

            if (typeof tags === 'string')

                tags = tags.split(spaceRe, 2);

 

            if (!isArray(tags) || tags.length !== 2)

                throw new Error('Invalid tags: ' tags);

 

            openingTagRe = new RegExp(escapeRegExp(tags[0]) '\s*');

            closingTagRe = new RegExp('\s*' escapeRegExp(tags[1]));

            closingCurlyRe = new RegExp('\s*' escapeRegExp('}' tags[1]));

        }

 

        compileTags(tags || mustache.tags);

 

        var scanner = new Scanner(template);

 

        var start, type, value, chr, token, openSection;

        while (!scanner.eos()) {

            start = scanner.pos;

 

            // Match any text between tags.

            // 开始扫描模板,扫描至{{时停止扫描,并且将此前扫描过的字符保存为value

            value = scanner.scanUntil(openingTagRe);

 

            if (value) {

                //遍历{{前的字符

                for (var i = 0, valueLength = value.length; i < valueLength; i) {

                    chr = value.charAt(i);

 

                    //如果当前字符为空格,则用spaces数组记录保存至tokens里的索引

                    if (isWhitespace(chr)) {

                        spaces.push(tokens.length);

                    } else {

                        nonSpace = true;

                    }

 

                    tokens.push([ 'text', chr, start, start 1 ]);

 

                    start = 1;

 

                    // 如果遇到换行符,则将前一行的空格去掉

                    if (chr === 'n')

                        stripSpace();

                }

            }

 

            // 判断下一个字符串中是否有{[,同时更新扫描索引至{{后一位

            if (!scanner.scan(openingTagRe))

                break;

 

            hasTag = true;

 

            //扫描标签类型,是{{#}}还是{{=}}还是其他

            type = scanner.scan(tagRe) || 'name';

            scanner.scan(whiteRe);

 

            //根据标签类型获取标签里的值,同时通过扫描器,刷新扫描索引

            if (type === '=') {

                value = scanner.scanUntil(equalsRe);

 

                //使扫描索引更新为s*=后

                scanner.scan(equalsRe);

 

                //使扫描索引更新为}}后,下面同理

                scanner.scanUntil(closingTagRe);

            } else if (type === '{') {

                value = scanner.scanUntil(closingCurlyRe);

                scanner.scan(curlyRe);

                scanner.scanUntil(closingTagRe);

                type = '&';

            } else {

                value = scanner.scanUntil(closingTagRe);

            }

 

            // 匹配模板闭合标签即}},如果没有匹配到则抛出异常,同时更新扫描索引至}}后一位,至此时即完成了一个模板标签{{#tag}}的扫描

            if (!scanner.scan(closingTagRe))

                throw new Error('Unclosed tag at ' scanner.pos);

 

            // 将模板标签也保存至tokens数组中

            token = [ type, value, start, scanner.pos ];

            tokens.push(token);

 

            //如果type为#或者^,也将tokens保存至sections

            if (type === '#' || type === '^') {

                sections.push(token);

            } else if (type === '/') {  //如果type为/则说明当前扫描到的模板标签为{{/tag}},则判断是否有{{#tag}}与其对应

 

                // 检查模板标签是否闭合,{{#}}是否与{{/}}对应,即临时保存在sections最后的{{#tag}},是否跟当前扫描到的{{/tag}}的tagName相同

                // 具体原理:扫描第一个tag,sections为[{{#tag}}],扫描第二个后sections为[{{#tag}} , {{#tag2}}]以此类推扫描多个开始tag后,sections为[{{#tag}} , {{#tag2}} ... {{#tag}}]

                // 所以接下来如果扫描到{{/tag}}则需跟sections的最后一个相对应才能算标签闭合。同时比较后还需将sections的最后一个删除,才能进行下一轮比较

                openSection = sections.pop();

 

                if (!openSection)

                    throw new Error('Unopened section "' value '" at ' start);

 

                if (openSection[1] !== value)

                    throw new Error('Unclosed section "' openSection[1] '" at ' start);

            } else if (type === 'name' || type === '{' || type === '&') {

                nonSpace = true;

            } else if (type === '=') {

                compileTags(value);

            }

        }

 

        // 保证sections里没有对象,如果有对象则说明标签未闭合

        openSection = sections.pop();

 

        if (openSection)

            throw new Error('Unclosed section "' openSection[1] '" at ' scanner.pos);

 

        //在对tokens里的数组对象进行筛选,进行数据的合并及剔除

        return nestTokens(squashTokens(tokens));

    }

 

  解析器就是用于解析模板,将html标签即内容与模板标签分离,整个解析原理为遍历字符串,通过最前面的那几个正则以及扫描器,将普通html和模板标签{{#tagName}}{{/tagName}}{{^tagName}}扫描出来并且分离,将每一个{{#XX}}、{{^XX}}、{{XX}}、{{/XX}}还有普通不含模板标签的html等全部抽象为数组保存至tokens。

 

  tokens的存储方式为:

 

    

 

  token[0]为token的type,可能值为:# ^ / & name text等分别表示{{#XX}}、{{^XX}}、{{/XX}}、{{&XX}}、{{XX}}、以及html文本等

 

  token[1]为token的内容,如果是模板标签,则为标签名,如果为html文本,则是html的文本内容

 

  token[2],token[3]为匹配开始位置和结束位置,后面将数据结构转换成树形结构的时候还会有token[4]和token[5]

 

  具体的扫描方式为以{{}}为扫描依据,利用扫描器的scanUtil方法,扫描到{{后停止,通过scanner的scan方法匹配tagRe正则(/#|^|/|>|{|&|=|!/)从而判断出{{后的字符是否为模板关键字符,再用scanUtil方法扫描至}}停止,获取获取到的内容,此时就可以获取到tokens[0]、tokens[1]、tokens[2],再调用一下scan更新扫描索引,就可以获取到token[3]。同理,下面的字符串也是如此扫描,直至最后一行return nestTokens(squashTokens(tokens))之前,扫描出来的结果为,模板标签为一个token对象,如果是html文本,则每一个字符都作为一个token对象,包括空格字符。这些数据全部按照扫描顺序保存在tokens数组里,不仅杂乱而且量大,所以最后一行代码中的squashTokens方法和nestTokens用来进行数据筛选以及整合。

 

  首先来看下squashTokens方法,该方法主要是整合html文本,对模板标签的token对象没有进行处理,代码很简单,就是将连续的html文本token对象整合成一个。

 

function squashTokens(tokens) {

        var squashedTokens = [];

 

        var token, lastToken;

        for (var i = 0, numTokens = tokens.length; i < numTokens; i) {

            token = tokens[i];

 

            if (token) {

                if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {

                    lastToken[1] = token[1];

                    lastToken[3] = token[3];

                } else {

                    squashedTokens.push(token);

                    lastToken = token;

                }

            }

        }

 

        return squashedTokens;

    }

 

   整合完html文本的token对象后,就通过nestTokens进行进一步的整合,遍历tokens数组,如果当前token为{{#XX}}或者{{^XX}}都说明是模板标签的开头标签,于是把它的第四个参数作为收集器存为collector进行下一轮判断,如果当前token为{{/}}则说明遍历到了模板闭合标签,取出其相对应的开头模板标签,再给予其第五个值为闭合标签的开始位置。如果是其他,则直接扔进当前的收集器中。如此遍历完后,tokens里的token对象就被整合成了树形结构

 

function nestTokens(tokens) {

        var nestedTokens = [];

 

        //collector是个收集器,用于收集当前标签子元素的工具

        var collector = nestedTokens;

        var sections = [];

 

        var token, section;

        for (var i = 0, numTokens = tokens.length; i < numTokens; i) {

            token = tokens[i];

 

            switch (token[0]) {

                case '#':

                case '^':

                    collector.push(token);

                    sections.push(token);   //存放模板标签的开头对象

 

                    collector = token[4] = [];  //此处可分解为:token[4]=[];collector = token[4];即将collector指向当前token的第4个用于存放子对象的容器

 

                    break;

                case '/':

                    section = sections.pop();   //当发现闭合对象{{/XX}}时,取出与其相对应的开头{{#XX}}或{{^XX}}

                    section[5] = token[2];

                    collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;  //如果sections未遍历完,则说明还是有可能发现{{#XX}}开始标签,所以将collector指向最后一个sections中的最后一个{{#XX}}

                    break;

                default:

                    collector.push(token);      //如果是普通标签,扔进当前的collector中

            }

        }

 

        //最终返回的数组即为树形结构

        return nestedTokens;

 

  经过两个方法的筛选和整合,最终出来的数据就是精简的树形结构数据:

        

 

   至此,整个解析器的代码就分析完了,然后我们来分析渲染器的代码。

 

   parseTemplate将模板代码解析为树形结构的tokens数组,按照平时写mustache的习惯,用完parse后,就是直接用 xx.innerHTML = Mustache.render(template , obj),因为此前会先调用parse解析,解析的时候会将解析结果缓存起来,所以当调用render的时候,就会先读缓存,如果缓存里没有相关解析数据,再调用一下parse进行解析。

 

Writer.prototype.render = function (template, view, partials) {

        var tokens = this.parse(template);

 

        //将传进来的js对象实例化成context对象

        var context = (view instanceof Context) ? view : new Context(view);

        return this.renderTokens(tokens, context, partials, template);

    };

 

  可见,进行最终解析的renderTokens函数之前,还要先把传进来的需要渲染的对象数据进行处理一下,也就是把数据包装成context对象。所以我们先看下context部分的代码:

 

 

function Context(view, parentContext) {

        this.view = view == null ? {} : view;

        this.cache = { '.': this.view };

        this.parent = parentContext;

    }

 

    /**

     * 实例化一个新的context对象,传入当前context对象成为新生成context对象的父对象属性parent中

     */

    Context.prototype.push = function (view) {

        return new Context(view, this);

    };

 

    /**

     * 获取name在js对象中的值

     */

    Context.prototype.lookup = function (name) {

        var cache = this.cache;

 

        var value;

        if (name in cache) {

            value = cache[name];

        } else {

            var context = this, names, index;

 

            while (context) {

                if (name.indexOf('.') > 0) {

                    value = context.view;

                    names = name.split('.');

                    index = 0;

 

                    while (value != null && index < names.length)

                        value = value[names[index ]];

                } else if (typeof context.view == 'object') {

                    value = context.view[name];

                }

 

                if (value != null)

                    break;

 

                context = context.parent;

            }

 

            cache[name] = value;

        }

 

        if (isFunction(value))

            value = value.call(this.view);

 

        console.log(value)

        return value;

    };

 

 

 

JavaScript中使用Object.create()创建对象介绍,javascript创建对象

对于对象的创建,除了使用字面量和new操作符,在ECMAScript 5标准中,还可以使用Object.create()来进行。Object.create()函数接受2个对象作为参数:第一个对象是必需的,表示所创建对象的prototype;第二个对象是可选的,用于定义所创建对象的各个属性(比如,writable、enumerable)。

复制代码 代码如下:

var o = Object.create({x:1, y:7});
console.log(o);//Object {x=1, y=7}
console.log(o.__proto__);//Object {x=1, y=7}

将null作为第一个参数调用Object.create()将生成一个没有prototype的对象,该对象将不会具有任何基本的Object属性(比如,由于没有toString()方法,对这个对象使用 操作符会抛出异常):

复制代码 代码如下:

var o2 = Object.create(null);
console.log("It is " o2);//Type Error, can't convert o2 to primitive type

对于仅支持ECMAScript 3标准的浏览器,可以用Douglas Crockford的方法来进行Object.create()操作:

复制代码 代码如下:

if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}
newObject = Object.create(oldObject);

对于对象的创建,除了使用字面量和new操作符,在ECMAScript 5标准中,还可以使用...

JavaScript中遍历对象的property的3种方法介绍,javascriptproperty

在JavaScript中,可以用三种方法来遍历对象的property:

1.for/in。可以使用for/in语句遍历对象自身的property(Own Property)及其从原型对象处继承的property,只有enumerable的property才会被遍历到。

2.Object.keys()。可以将对象作为参数传入Object.keys(),Object.keys()语句将返回由所有property名称字符串所组成的数组。Object.keys()语句仅返回对象自身的(Own Property)且enumerable的property。该语句仅在ECMAScript 5标准中有效。

3.Object.getOwnPropertyNames()。可以将对象作为参数传入Object.getOwnPropertyNames(),与Object.keys()一样,该语句将返回由所有property名称字符串所组成的数组。与Object.keys()不同的是,Object.getOwnPropertyNames()语句将返回所有对象自身的property(Own Property),而不论其是否为enumerable。该语句仅在ECMAScript 5标准中有效。

综合上述信息,总结成图如下:

图片 1

实验:

复制代码 代码如下:

var o = {x:1, y:2};
var a = Object.create(o);
a.z = 3;

for(p in a){
  console.log(p);
}//z x y
console.log(Object.keys(a));//["z"]
console.log(Object.getOwnPropertyNames(a));//["z"]

在JavaScript中,可以用三种方法来遍历对象的property: 1.for/in。可以使用for/in语句...

本文由小鱼儿玄机30码发布于小鱼儿主页高手论坛,转载请注明出处:还可以使用Object.create()来进行,因为之前接手的

关键词: 小鱼儿玄机30码