Javasvript中一些奇怪的问题(JS笔记)

目录

首先

在echarts中,修改地图的边界的颜色

     geo: {
        map: 'china',
        label: {
            emphasis: {
                show: false
            }
        },
        roam: true,
        itemStyle: {
            normal: {
                areaColor: '#323c48', //这里是这是地图边界颜色的
                borderColor: 'red'
            },
            emphasis: {
                areaColor: '#2a333d'
            }
        }
    }

这段代码来自于http://echarts.baidu.com/demo.html#heatmap-map

然后,开始一段新的征程

一些有趣的获取每个月多少天的代码

我常用的写法(非常普通的)

function getMonthDays(time) {
    var year = parseInt(time);
    var month = Number(time.substr(-2));
  return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month-1] || (isLeapYear(year) ? 29 : 28);
}

高级那么一丁点的写法(这个和我用的差不多)

const EVERY_MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

function getDays(year, month) {
  if (month === 1 && isLeap(year)) return 29;
  return EVERY_MONTH_DAYS[month];
}
function isLeap(year){
     return ((year%4==0&&year%100!=0)||(year%400==0))
}

炫酷一点点的写法(第三个参数可以是可以大于我们所知道的每个月的最后一天的)

function getDays(year, month) {
  if (month === 1) return new Date(year, month, 29).getMonth() === 1 ? 29 : 28;
  return new Date(year, month, 31).getMonth() === month ? 31 : 30;
}

屌炸天的写法(跟上面一样,不过第三个参数传0,他就会显示上个月的最后一天是几号)

function getDays(year, month) {
  return new Date(year, month + 1, 0).getDate();
}

接着,我们来看一下把时间转换为标准格式的方法

同样,白痴的方法(实际上并不白痴,很使用的一种方法)PS:注意最後的正则使用的很好

let date = new Date();
let result = [
  [
    date.getFullYear(),
    date.getMonth() + 1,
    date.getDate()
  ].join('-'),
  [
    date.getHours(),
    date.getMinutes(),
    date.getSeconds()
  ].join(':')
].join(' ').replace(/\b\d\b/g, '0$&');//匹配边界然后加上0,正则匹配只有一位数字的加上0

精妙的方法

var date = new Date();
var result = date.toLocaleString('zh-CN', { hour12: false })
  .replace(/\//g, '-').replace(/\b\d\b/g, '0$&');

下面我们来看看一些比较杂乱的东西

都是我一点点总结出来的,有的没写答案

变量提升的问题

// 调用被提升的函数
addition(4, 7); // => 11// 变量被提升了,但值是undefined
substraction(10, 7); // TypeError: substraction is not a function
// 函数声明
function addition(num1, num2) {
   return num1 + num2;}// 函数表达式var substraction = function (num1, num2) {
  return num1 - num2;};

addition被彻底的提升并且可以在声明之前被调用。然而substraction是使用变量声明语句声明的,虽然也被提升了,但被调用时值是undefined。因此会抛出异常TypeError: substraction is not a function。

再来看这个变量提升的问题,关于ES6的

function isTruthy(value) {
  var myVariable = 'Value 1';
  if (value) {
    /**
     * myVariable的临时死亡区间
     */
    console.log(myVariable);// Throws ReferenceError: myVariable is not defined
    let myVariable = 'Value 2';
    // myVariable的临时死亡区间至此结束
    console.log(myVariable); // => 'Value 2'
    return true;
  }
  return false;}
isTruthy(1); // => true
    从let myVariable一行一直到代码块开始的if (valaue) {...}都是myVariable变量的临时死亡区间。如果在此区间内访问该变量,JavaScript会抛出ReferenceError异常。
    一个有趣的问题出现了:myVariable真的被提升到代码块顶部了吗?还是在临时死亡区间内未定义呢?当一个变量未被定义时,JavaScript也会抛出ReferenceError。
    如果你观察一下该函数的开始部分就会发现,var myVariable = 'Value 1'在整个函数作用域内定义了一个名为myVariable的变量。在if (value) {...}块内,如果let定义的变量没有被提升,那么在临时死亡区间内myVariable的值就会是'Value1'了。由此我们可以确认块级变量确实被提升了。
    let在块级作用域内的提升保护了变量不受外层作用域影响。在临时死亡区间内访问let定义的变量时抛出异常会促使开发者遵循更好的编码实践:先声明,后使用。
    这两个限制是促使在封装性和代码流程方面编写更好的JavaScript的有效途径。这是基于var用法教训的结果 —— 允许在声明之前访问变量很容易造成误解。

来模拟一个map的方法

Array.prototype.map = function(fn){
    var a = [];
    for(var i = 0; i < this.length; i++){
        var value = fn(this[i], i);
        if(value == null){
            continue; //如果函数fn返回null,则从数组中删除该项
        }
        a.push(value);
    }
    return a;
};
array.map(callback[, thisArg]);
  map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值组合起来形成一个新数组。 callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。callback 函数会被自动传入三个参数:数组元素,元素索引,原数组本身。如果 thisArg 参数有值,则每次 callback 函数被调用的时候,this 都会指向 thisArg 参数上的这个对象。如果省略了 thisArg 参数,或者赋值为 null 或 undefined,则 this 指向全局对象 。
  map 不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)。当一个数组运行 map 方法时,数组的长度在调用第一次callback 方法之前就已经确定。在 map 方法整个运行过程中,不管 callback 函数中的操作给原数组是添加还是删除了元素。
  map 方法都不会知道,如果数组元素增加,则新增加的元素不会被 map 遍历到,如果数组元素减少,则 map 方法还会认为原数组的长度没变,从而导致数组访问越界。如果数组中的元素被改变或删除,则他们被传入 callback 的值是 map 方法遍历到他们那一刻时的值。

另一种方法

if (!Array.prototype.map)
{
    Array.prototype.map = function(fun /*, thisp*/)
    {
        var len = this.length;
        if (typeof fun != "function")
            throw new TypeError();

        var res = new Array(len);
        var thisp = arguments[1];
        for (var i = 0; i < len; i++)
        {
            if (i in this)
                res[i] = fun.call(thisp, this[i], i, this);
        }

        return res;
    };
}

Object.create

Object.create(proto [, propertiesObject ]) 是E5中提出的一种新的对象创建方式,第一个参数是要继承的原型,如果不是一个子函数,可以传一个null,第二个参数是对象的属性描述符,这个参数是可选的。创建原型继承
propertiesObject 参数的详细解释:(默认都为false)
数据属性:
writable:是否可任意写
configurable:是否能够删除,是否能够被修改
enumerable:是否能用 for in 枚举
value:值
访问属性:
get(): 访问
set(): 设置

两种不常见的css隐藏

.hide{position: absolute;top: -9999px;left: -9999px; }
.hide{ clip-path: polygon(0px 0px,0px 0px,0px 0px,0px 0px); }

css模拟拿起放下的效果

<div class = "floating"></div>
.floating {
    position: relative;
    width:100px;
    height:100px;
    bbackground:red;
    transform: translateY(0);
    transition: transform 1s;}

.floating:after {
    content: "";
    display: block;
    position: absolute;
    bottom: -30px;
    left: 50%;
    height: 8px;
    width: 100%;
    box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, 0.4);
    border-radius: 50%;
    background-color: rgba(0, 0, 0, 0.2);

    transform: translate(-50%, 0);
    transition: transform 1s;}

/* Hover States */.floating:hover {
    transform: translateY(-40px);
    transition: transform 1s;}.floating:hover:after {
    transform: translate(-50%, 40px) scale(0.75);
    transition: transform 1s;}

下面进入正题this的一些问题

题1.

// 写出以下代码的运行结果
var a = 1;
function fn() {
    if (!a) {
        var a = 2; //这里的var会提升到fn下面
    }
    alert(a); // ?   2
}
fn();

题2

// 写出以下代码的运行结果
var a = 1;
function fn() {
    a = 2;
    return;
    function a() {}  //首先会提升到fn下面,然后a是局部变量 
                     //注意变量与函数同名之后,变量相当于局部变量了,函数提升为a = function(){}
}
fn();
alert(a); // ?   1

题3

    a= 10;  
    (function a(){  
         a = 1;  
         console.log(a);// ?  functiona(){   a是function,匿名函数的函数名可以在函数内部访问
                        //       a = 1;  
                        //       console.log(a);
                        //   }
     })();  

题4

function a(){
    console.log(aa);   //这里aa是undefined,在不同的浏览器下不一样,最新版chrome是undefined,其他的都是function
        if(1){
         function aa(){
            console.log(11);
        }
    }   
}

题5

var a = 1,
    b = function a (x) {  //b是局部变量
        x && a (--x);
    };
alert (a);
alert(b(a));//undifined,最后函数返回0

我们可以用多个逗号将变量分开定义,而是用一个var。函数表达式类似于局部变量,不会被全局作用域中访问到。
    执行顺序:
       声明两个变量var a,b;
       并给他们赋值a=1,b=function a(){...};
       这里的function a是局部变量,外部无法访问到。
       因此全局a还是1.

题6

var test =  111;
function _add()  
{  
   // this.test = 444;  //注释①
    alert(this.test);  
}  
function _sub()  
{  
    this.test = 222;
    alert(this.test);  
}  
  _add();           
  _sub();
_add.call(_sub);   //有注释①:undefined  去掉:444,this指向sub,这是sub执行add里面的方法,然后调用的add的方法this.test = 444;
var d = new _add();//结果等同于_add.call(_sub);
a.call(b)里面的是作用域相当于在b里面执行a的方法,a.call(this)这个this是window,在window里面执行a的方法 

题7

var name = 1;
function show(){
    console.log(name);//1,因为show没有参数,所以name传不进来!!!WTF
}
function main(){
    var name =2;
    show();
}
main()

题8

function a(xx){
 this.x=xx;
 return this
};
var x=a(5);
var y=a(6);   //注意是两句运行完之后再打印的
console.log(x.x);  //undefined
console.log(y.x); //6

题9 http://www.cnblogs.com/xxcanghai/p/5189353.html

function Foo() {
    getName = function () { alert (1); };
    return this;
}
Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
var getName = function () { alert (4);};
function getName() { alert (5);}

//请写出以下输出结果: 
Foo.getName();   //2
getName(); //4
Foo().getName();//5   1 //重新定义window.getName
getName();//4   1
new Foo.getName();//2   只有函数才能new,单对象new {} 是错误的
new Foo().getName();//1   3
new new Foo().getName(); //3   执行顺序new((new Foo)().getName)()

这是对 this 的描述

 https://segmentfault.com/q/1010000003019911
 JavaScript 中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里。
                                                       ----(JavaScript 高级程序设计)

我知道 this 的指向一般分 4 种情况:

(1)作为构造函数调用,指向构造函数生成的对象;
(2)作为函数调用,指向去全局变量
(3)作为对象的方法调用,指向到该对象
(4)使用 call 或者 apply 方法,this 指定 call 或者 apply 方法指定的执行环境。。

继续做题

题10

ar length = 10;
function fn(){
    alert(this.length);
}
var obj = {
    length: 5,
    method: function(fn) {
        fn() // 10    这里得fn跟不是传进来的参数,只是调用外部的函数所以this是全局
        arguments[0]() // 1 这里是传参进来的fn,但是他的作用域是arguments,所以是1
    }
}
obj.method(fn)

题11

~function() {   //~表示匿名函数
    alert(typeof next) // undefined
    ~function next() {
        alert(typeof next) // function
    }()
}()

题12

var a=function b(){};
    alert(typeof b);

    根据 ECMA 规范中的规定,以上函数表达式中的标识符 b 将仅在该函数的内部可以被访问,即 b 仅在该函数的作用域内有效,外部无法访问。

题13

function a(b){                                             function a(b){ //b传值进来就被覆盖了    //http://blog.csdn.net/zxc123e/article/details/37052155

    alert(b);                                                   var b = function(){                                    

    function b(){                                                 alert(b);
        alert(b);                                                 }
    }                                                            alert(b);
    b();                                                       b();
}                                                            }
a(1);                                                       a(1);

题14

(function(){
  var a = b = 3; //b是全局啊!!!!
})();

console.log(a); //undefined
console.log(b); //3

题15

function foo1() //http://www.2cto.com/kf/201512/454888.html
{
  return {
      bar: "hello"
  };
}


function foo2()
{
  return
  {
      bar: "hello"
  };
};

foo1();
foo2();     

题16

function add(num1, num2){ //js精度问题处理加法
  let r1, r2, m;
  r1 = (''+num1).split('.')[1].length;
  r2 = (''+num2).split('.')[1].length;

  m = Math.pow(10,Math.max(r1,r2));
  return (num1 * m + num2 * m) / m;
}
console.log(add(0.1,0.2));   //0.3
console.log(add(0.15,0.2256));

题17

//写一个少于 80 字符的函数,判断一个字符串是不是回文字符串

function isPalindrome(str) {
    str = str.replace(/\W/g, '').toLowerCase();
    return (str == str.split('').reverse().join(''));
}

题18

CSS计数器只能跟content属性在一起的时候才有作用,counter 只能在content 里面使用,而content属性貌似专门用在before/after伪元素上的。于是,就有了,“计数器↔伪元素↔content属性”的铁三角关系。
.xxx { counter-reset: wangxiaoer 2 wangxiaosan 3; } //对counter进行初始化,中间只能用空格分隔
counter-reset还可以设置为none和inherit. 干掉重置以及继承重置。
counter-increment使用一次,counter-reset值增加,默认递增1

题19

 //数组去重
  if(!Array.prototype.unqine){
    Array.prototype.unqine = function(){
        var a =[];//定义一个临时数组用于装数据
        for(var i = 0; i < this.length; i++){
            if(a.indexOf(this[i]) === -1) a.push(this[i]);
        }
        return a;
    }
}

var arr = [8,8,8,8,8,8,9,0,1,5,6,7,8,1,4,3,2,4];
console.log(arr.unqine());//[8, 9, 0, 1, 5, 6, 7, 4, 3, 2]

//兼容IE
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(val) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] === val)return i;
        }
        return -1;
    }
}
2016/8/3
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值