一般人不清楚的JavaScript概念

本文深入探讨了JavaScript中六个核心概念:字面量、立即执行函数、属性与扩展属性、混入、垫片与变通实现及纯JavaScript的含义。通过具体示例详细解释了这些概念的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注:以下部分代码或术语涉及ECMAScript 6。

1. literal

literal(字面量)即开发者写的,可直接被解析器识别,不必显式依赖API创建的量。如:

  • 数字literal:123, 0b1111011, 0o173, 0x7B
  • 字符串literal:"123", `12{2+1}`
  • 数组literal:[1,2,8]
  • 对象literal:{A:1,B:2,C:8}
  • 正则表达式literal:/^\d+(?:\.\d+)?$/
  • 其他literal:true, false, null

2. IIFE

还记得为了闭包(closure)而编写的声明即执行的函数表达式吗?这种函数表达式是IIFE,读作[iffy]。

var chars=//charCode为0x20,0x21,...,0x7F的一组字符组成的字符串,由以下IIFE表示
(function(){
    var a=[];
    for(let i=0x20;i<0x80;i++){
        a.push(i);
    }
    return String.fromCharCode.apply(String,a);
})();

3. property and expando

property对于一般JavaScript开发者来说,熟悉而又陌生:
一个object的property含property key和property descriptor两部分。
property key分string和symbol两种。
property descriptor分data descriptor和accessor descriptor两种。
data descriptor有固定的value,而accessor descriptor有getter与/或setter。
property descriptor中的enumerable,configurable分别表示property是否可枚举,是否可重定义。

expando是property的一个形容词,指在规范之外扩展的,仅供实现者内部使用的。
对于jQuery而言,jQuery.fn属性可算作一个expando property。

举例:

var lengthExpando=Symbol.for("length");
function ArrayLike(){
    var length=0;
    // ...
    Object.defineProperty(
        this,
        lengthExpando,// symbol as a property key
        {enumerable:false,configurable:true,value:length}// data descriptor
    );// define an expando property
    Object.defineProperty(
        this,
        "length",// string as a property key
        {
            enumerable:false,
            configurable:true,
            get:function(){
                return this[lengthExpando];
            },
            set:function(value){
                var num=+value;
                var len=num>>>0;
                if(len!=num){
                    throw new RangeError("Invalid length");
                }
                // ...
                this[lengthExpando]=len;
            }
        }// accessor descriptor
    );// define a spec-defined property
}

4. mixin

与plugin可被安装到兼容的宿主程序的概念类似,mixin是一个class/object,它的属性/方法可动态复制到其他适配的class/object。
举例:

// define a mixin which is compatible with any Array-like class or object
var ArrayLikePrototype={
    get firstElement(){
        var index=0;
        if(index<this.length){
            return this[index];
        }
        //return undefined;
    },
    getFirstElement(){
        var index=0;
        if(index<this.length){
            return this[index];
        }
        //return undefined;
    },
    get lastElement(){
        var index=this.length-1;
        if(index>-1){
            return this[index];
        }
        //return undefined;
    },
    getLastElement(){
        var index=this.length-1;
        if(index>-1){
            return this[index];
        }
        //return undefined;
    },
    // ...
};

// mix `ArrayLikePrototype` in `NodeList.prototype`
Object.defineProperties(NodeList.prototype,Object.getOwnPropertyDescriptors(ArrayLikePrototype));

// mix `ArrayLikePrototype` in `HTMLCollection.prototype`
Object.defineProperties(HTMLCollection.prototype,Object.getOwnPropertyDescriptors(ArrayLikePrototype));
//so that `document.children.firstElement` will be document.children[0]

// or even mix `ArrayLikePrototype` in `Array.prototype`
Object.defineProperties(Array.prototype,Object.getOwnPropertyDescriptors(ArrayLikePrototype));
//so that `[1,2,3].lastElement` will be 3, and `[1,2,3].getLastElement()` will be 3 too

5. shim and polyfill

shim 是为修正运行环境API而编写的代码。如:

// shim Window#setTimeout()
if(document.documentMode==9&&!Object.prototype.hasOwnProperty.call(window,"setTimeout")){
    var WindowSetTimeout=Window.prototype.setTimeout;
    Window.prototype.setTimeout=function setTimeout(callback, delay){
        if(arguments.length<3||typeof callback!="function")
            return WindowSetTimeout.call(this, callback, delay);
        var args=Array.prototype.slice.call(arguments, 2);
        return WindowSetTimeout.call(this, function(){
            callback.apply(this, args);
        }, delay);
    };
}

//shim window.Event
if(document.documentMode>8&&typeof window.Event=="object"){
    var nativeEvent=window.Event;
    var shimedEvent=function Event(type/*,eventInit*/){
        if(!(this instanceof Event))
            throw new TypeError("Failed to construct 'Event': Please use the 'new' operator, this DOM object constructor cannot be called as a function.");
        if(arguments.length===0)
            throw new TypeError("Failed to construct 'Event': An event type must be provided.");
        var event=document.createEvent("Event"),
            eventInit={bubbles:false,cancelable:false},
            p=Object.assign(eventInit,arguments[1]);
        event.initEvent(type,p.bubbles,p.cancelable);
        return event;
    };
    shimedEvent.prototype=nativeEvent.prototype;
    window.Event=shimedEvent;
}

polyfill是为填补运行环境缺失的功能而提供的变通实现代码。如:

// polyfill Object.assign()
if(typeof Object.assign!="function"){
    Object.assign=function assign(object,source){
        var to,from,sources,nextSource,i,j,len,keys,key;
        //#1
        if(object==null)
            throw new TypeError("Cannot convert "+object+" to Object");
        to=Object(object);
        //#3
        if(arguments.length===1)
            return to;
        //#4
        sources=Array.prototype.slice.call(arguments,1);
        //#5
        for(i=0; i<sources.length; i++){
            //#a
            nextSource=sources[i];
            if(nextSource==null){continue;}
            //#b
            from=Object(nextSource);
            //#d
            keys=Object.keys(from);
            //#e
            len=keys.length;
            //#f
            for(j=0;j<len;j++){
                key=keys[j];
                to[key]=from[key];
            }
        }
        //#6
        return to;
    };
}
// polyfill HTMLElement#hidden
if(typeof document.documentElement.hidden!="boolean"){
    Object.defineProperty(HTMLElement.prototype,"hidden",{
        get:function getHidden(){
            return this.getAttribute("hidden")!=null;
        },
        set:function setHidden(v){
            if(v)
                this.setAttribute("hidden", "");
            else
                this.removeAttribute("hidden");
        }
    });
}

6. SemVer

越扯越远,这一条似乎与JavaScript不相关。

平时我们看到的一些软件库文件名如jquery-2.1.3.js,知道其中的版本号2.1.3遵循X.Y.Z,但XYZ每部分的含义,升级规则和比较/排序规则却又不清楚。
为了定义一个通用的版本号标准,GitHub联合创始人Tom Preston-Werner编写了SemVer(Semantic Versioning)规范。
SemVer 2.0.0规范定义的版本号的格式如下:
major . minor . patch [ - pre] [ + build]
一个SemVer版本号不仅仅代表着一个独特的版本,还牵涉到其背后一系列的排序/升级/关联/筛选规则。

7. vanilla

这里的vanilla指寻常的,无特色的。vanilla js用中文说即纯手工编写,未用到第三方框架的js。

VanillaJS是一个没有可运行代码的JavaScript框架,通常被用作愚人节玩笑。它列举一些直接调用原生API而不必借助框架的实践方式,并突出这些寻常代码相对基于框架调用的代码所带来的性能优势,其思想有种道家无为的意味。但恰恰其他框架在试图证明使用框架后相对VanillaJS所带来的兼容/易用优势。

to be continued

更多见 MDN词汇表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值