zoukankan      html  css  js  c++  java
  • JS一些有趣的知识(更新中)

    一、变量提升

    console.log(a); //undefined    
    var a = 0;

    以上代码段并不会报错,js中存在变量提升,会将变量的声明提升至文件的顶部,形式如下。

    var a;
    console(a);
    a = l;

    函数会不会存在变量提升呢?答案是显然的。

    f();
    function f(){}

    表面上好像是f()在声明前已经被调用了,由于变量提升f()被提升到了代码头部,但是采用复制语句定义函数会报错。

    f();
    var f = function(){};
    //TypeError: undefined is not a function
    
    /*
    because:
    var f;
    f();
    f = function(){}
    */

    二、label

    var a = 0;
    loop:
    for(let i=0;i<10;i++){
        for(let j=0;j<10;j++){
            a++;
            break loop;
        }
    }
    console.log(a); //1

    以上loop为一个label,label多用来break或continue跳出代码块。

    三、null与undefined

    null与undefined在if语句中被转换为false。

    null是一个表示为“空”的对象,它的出生较早(1995),根据C语言的传统,可以自动转换为0.

    Number(null); //0
    null+5; //5

    undefined表明此处无定义的原始值

    Number(undefined); //NaN
    undefined+6; //NaN

    如果JavaScript预期某个位置应该是布尔值,以下值会转换为false: undefined, null, false, 0, NaN, ""或''(空字符串);而其他值都是为true.

    NaN不是独立的数据类型,是一个特殊的数值,数据类型仍然属于Number。

    四、console

    var languages = [
      { name: "JavaScript", fileExtension: ".js" },
      { name: "TypeScript", fileExtension: ".ts" },
      { name: "CoffeeScript", fileExtension: ".coffee" }
    ];
    
    console.table(languages);

    console.table()可以将对象以表格的形式打印。

    console.time(), console.timeEnd()计算时间

    五、defineProperty

    var extend1 = function (to, from) {
      for (var property in from) {
        if (!from.hasOwnProperty(property)) continue;
        Object.defineProperty(
          to,
          property,
          Object.getOwnPropertyDescriptor(from, property)
        );
      }
    
      return to;
    }
    
    var extend2 = function (to, from) {
      for (var property in from) {
        to[property] = from[property];
      }
    
      return to;
    }
    var bak1 = {};
    var bak2 = {};
    extend1(bak1, { 
        a:1,
        get getter(){ return this.a }, 
        set setter(a) {console.log("a"+a)}
    });
    extend2(bak2, { 
        a:1,
        get getter(){ return this.a }, 
        set setter(a) {console.log("a"+a)}
    });
    console.dir(bak1);
    console.dir(bak2);

    extend1,extend2分别为两个对象copy的方法,而extend2无法copy存储器定义的属性(只能copy到它的值),所以我们要采用extend1来copy对象,结果如下:

    六、对象的冻结

    对象的冻结有三种方法:

    1. Object.preventExtensions(obj)    //该方法冻结后,对象无法添加新属性
      1. Object.isExtensible(obj)    //该方法用来检验对象是否采用上诉方法冻结
    2. Object.seal(obj)    //该方法冻结后,对象无法添加新属性,无法删除旧属性(实质是把对象的configurable设为false)
      1. Object.isSealed(obj)    //检查该对象是否采用上诉方法冻结
    3. Object.freeze(obj)    //无法添加新属性、无法删除旧属性、也无法改变属性的值,使得这个对象实际上变成了常量
      1. Object.isFrozen(obj)    //检查该对象是否采用上诉方法冻结

    局限性:可以通过改变原型改变对象(可以把原型也冻住),如果该对象是数组,只是冻结了数组,没有冻结数组的内容。

     六、数组

    你想在JS中形成栈结构吗?很简单,数组+push()+pop()可以实现

    var array = [];
    array.push('a');
    array.push('b');
    array.pop(); 
    //a

    队列:数组+push()+shift()

    七、this对象

    一谈起this,我们都知道是再说当前对象。但是当前对象又总是显得那么抽象,所以理解起来也显得有些无力了。

    那么this到底是什么东西,我觉得可以理解为当前(runtime)的一个环境,举例如下:

    var a=1;
    var f = function(){
      console.log(this.a);
    }
    var obj = {
      a:2,
      f:f          
    };
    f();    //1
    obj.f();    //2

    先说直接调用f(),因为对于f来讲,f在全局环境执行;而对于obj.f()来讲,obj.f的执行是在obj对象的内部环境,所以导致了结果的不同。

    八、call, apply, bind

    JS提供了call, apply, bind来切换this的指向。

    call不传入参数或传入undifined,null。则默认传入全局值(window)。

    var n = 123;
    var obj = { n: 456 };
    
    function a() {
      console.log(this.n);
    }
    
    a.call() // 123
    a.call(null) // 123
    a.call(undefined) // 123
    a.call(window) // 123
    a.call(obj) // 456
    func.call(thisValue, arg1, arg2, ...):在thisValue的上下文环境中调用func, arg1, arg2...是func所需参数
    call常见套路:
    var obj = {};
    Object.prototype.hasOwnProperty.call(obj, 'toString') // false

    hasOwnProperty方法的原始定义放到obj对象上执行,这样无论obj上有没有同名方法,都不会影响结果。

    apply与call相似,不过func.apply(thisValue, [arg1, arg2, ...])的参数是一个数组。

    bind方法用于将函数体内的this绑定到一个对象上。因为bind方法每次会返回一个新方法,如果没有变量名来接收它,则会产生一个匿名函数,这样就会出现一些奇怪的问题

    e.g.:如果通过element.addEventListener("click",o.m.bind(o));来添加click监听则会出现remove不了监听的情况发生。

    九、JS的模块封装

    可以利用JS的立即执行函数起着封装模块的作用,代码如下:

    (function($, window, document) {
    
      function go(num) {
      }
    
      function handleEvents() {
      }
    
      function initialize() {
      }
    
      function dieCarouselDie() {
      }
    
      //attach to the global scope
      window.finalCarousel = {
        init : initialize,
        destroy : dieCarouselDie
      }
    
    })( jQuery, window, document );

    通过finalCarousel对象将init,destory暴露出来,其余内部方法无法访问。

    十、proxy

    proxy用于修改某些操作的默认行为,在语言层面上作出修改。可以理解成,在目标之前设立了“拦截”,外界对该对象的访问都必须先通过这层拦截。

    var object = { proxy: new Proxy(target, handler) };
    

     如果handler上没有设置任何拦截,等同于直接通向原对象。

  • 相关阅读:
    JSONObject简介
    android:layout_gravity 和android:gravit的区别?
    CountDownTimer,0,0
    java应用集锦9:httpclient4.2.2的几个常用方法,登录之后访问页面问题,下载文件
    HttpClient学习系列 -- 学习总结
    创建多线程的HttpClient
    HttpClient4.X 升级 入门 + http连接池使用
    Java Executors(线程池)
    [微软官方]SQLSERVER的兼容级别
    vSphere Client 连接ESXi 或者是vCenter 时虚拟机提示VMRC异常的解决办法
  • 原文地址:https://www.cnblogs.com/popcornya/p/JS.html
Copyright © 2011-2022 走看看