Javascript 容易忽视的语法点

  1. 使用 typeof bar === “object” 判断 bar 是不是一个对象有何潜在的弊端?如何避免这种弊端?
    var arr = [];
    var obj = {};
    var nl  =  null;

    console.log(typeof arr === 'object'); //true
    console.log(typeof obj === 'object'); //true
    console.log(typeof nl  === 'object'); //true
// 从上面的输出结果可知, 使用 typeof 并不能准确判断 bar 就是一个 Object。
// 可以通过 Object.prototype.toString.call(bar) === "[object Object]" 来避免这种弊端:
    console.log(Object.prototype.toString.apply(arr)); 
    //[object Array]

    console.log(Object.prototype.toString.apply(obj));
    //[object Object]

    console.log(Object.prototype.toString.apply(nl));
    // [object Null]
另外,在控制台检查会发现,
 if([])
  {
    console.log('[] is true')
  }  点击Enter键
[] is true
undefined
[]==true  点击Enter键
false
[]===true 点击Enter键
false

[]==false   点击Enter键
true ([]和 false值相同 )
[]===false  点击Enter键
false ([]和 false类型不相同,===三个等号表示值和类型都相同)
[object Array] VS [object Boolean]

2.下面的代码会在 console 输出神马?为什么?

(function(){
 var a = b = 3;
})();

console.log("a defined? " + (typeof a !== 'undefined')); 
console.log("b defined? " + (typeof b !== 'undefined'));
    // 函数所创建的作用域中的局部变量,JS中只有函数可以创建作用。
    // JS不存在块级作用域
    // JS中是词法作用域(与之对立的为动态作用域),在代码写好的那一刻,作用域就已经确定了
    // 词法作用域的规则:
    // 函数允许访问函数外的数据
    // 如果当前作用域中有了该变量,就不考虑外面的同名变量
    (function() {
        var a = b = 3;
        // 这一句等价于:
        // b = 3;     全局变量
        // var a = b; 
    })();
    console.log(a); //  Uncaught ReferenceError: a is not defined  报错后,后面的不执行,要想后面代码执行,需要屏蔽这一句。
    console.log(typeof a); // undefined
    console.log(b); //3

    console.log("a defined? " + (typeof a !== 'undefined')); //false
    console.log("b defined? " + (typeof b !== 'undefined'));
    // true

3.下面的代码会在 console 输出神马?为什么?

    var myObject = {
        foo: "bar",
        func: function() {
            var self = this;
            console.log("outer func: this.foo = " + this.foo);
            console.log("outer func: self.foo = " + self.foo);
            (function() {
                console.log("inner func: this.foo = " + this.foo);
                console.log("inner func: self.foo = " + self.foo);
            }());
        }
    };
    myObject.func();

我们在sublime中写出来,实践出真知:

    var myObject = {
        foo: "bar",
        func: function() {
            var self = this; 
            //self指的是myObject对象
            console.log(this); 
            //这里的this指的是myObject对象

            console.log("outer func: this.foo = " + this.foo);
            // bar !!
            console.log("outer func: self.foo = " + self.foo);
            // bar

            (function() {
                console.log(this);//这里的thiswindow
                console.log(self); //self就是myObject

                console.log("inner func: this.foo = " + this.foo);
                // undefined window上是没有foo属性的
                console.log("inner func: self.foo = " + self.foo);
                // bar
            }());
        }
    };
    myObject.func();
第一个和第二个的输出不难判断,self和this都是指的调用func的对象myObject,所以打印结果都是bar。
对于第三个,因为 this (指的是window)在可访问到的作用域内是 undefined,第四个输出是 undefined。
在 ES6 之前,JavaScript 只有函数作用域,所以 func 中的 IIFE 有自己的独立作用域,并且它能访问到外部作用域中的 self,所以第四个打印也是bar。

如果你知道闭包,下面的内容也是很好理解的:

    var myObject = {
        foo: "bar",
        func: function() {
            var self = this;
            (function(test) {
                // 当myObject.func();执行完毕后,下面的IIFE等于放在最外层执行,此时的this指的是window
                console.log("inner func: this.foo = " + this.foo); //'bar'

                // 这里实参传递给形参等价于下面两行代码
                // var test;
                // test = self;
                console.log(self); //self就是myObject
                console.log(test); //test就是self也即myObject
                console.log("inner func: this.foo = " + test.foo); //'bar'
                console.log("inner func: self.foo = " + self.foo);
            }(self));

        }
    };
    myObject.func();

4.将 JavaScript 代码包含在一个函数块中有什么意思呢?为什么要这么做?
这个问题其实就是看你是否掌握了闭包,关于闭包我打算专门写一篇博文,这个问题也可以理解为,IIFE的作用是什么
IIFE即是: 立即执行函数表达式(Immediately-Invoked Function Expression)
先看下下面这段代码:

    for(var i =0;i<6;i++){
        setTimeout(function(){
            console.log(i);
        }, 1000);
    }
打印结果是什么呢?
六个6
很经典的一个问题:
所有的主任务的代码执行完毕之后,去检查所有的setTimeout回调函数,如果到时间了就执行,此时i已经变为6了。
可以用闭包来解决这个问题,关于闭包,我总结了三个关于闭包的特点,其实不用看我的总结,只要你观察下闭包,基本上也就是这三个特点:
    // 1.IIFE
    // 2.函数里面的内容不会立即执行,调用的时候(时间到了或者用户点击的时候)才会执行
    // 3.1 函数里面内容虽然不会立即执行,如果再每次循环阶段(预解析阶段)把值以函数参数的形式传进去之后,在函数执行阶段,用的就是当时传进去的值
    // 3.2 函数里面内容虽然不会立即执行,如果在内层作为返回值return出来的函数中,定义一个变量,引用了外层的变量,那么执行阶段,用的就是预解析阶段引用的值
   好,我们看下钢材那个问题,如果想要输出012345该怎么改写代码
       for (var i = 0; i < 6; i++) {
        function foo(j) {
            return function() { /第2条
                console.log(j);
            }
        }
        var f = foo(i); //第1条  第3.1条(至于第3.2条,等我专门写闭包了再讲吧)
        setTimeout(f, 1000);
    }


好了上面是IIFE的第一个常用之处。
----------


 另外 JQuery/Node 的插件和模块开发中,为避免变量污染,也是一个大大的 IIFE:
(function($) { 
 //代码
 } )(jQuery);

而不是直接的
function(){
    jQuery...
}

5.下面两个函数的返回值是一样的吗?为什么?

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

    function foo2() {
        return  //这里换行
        {
            bar: "hello"
        };
    }
    var o1 = foo1();
    var o2 = foo2();
    console.log(o1.bar); //hello
    console.log(o2.bar); //Uncaught TypeError: Cannot read property 'bar' of undefined
在编程语言中,基本都是使用分号(;)将语句分隔开,这可以增加代码的可读性和整洁性。
而在JS中,如若语句各占独立一行,通常可以省略语句间的分号(;),JS 解析器会根据能否正常编译来决定是否自动填充分号:
var test = 1 + 
2
console.log(test); //3
在上述情况下,为了正确解析代码,就不会自动填充分号了,但是对于 returnbreakcontinue 等语句,如果后面紧跟换行,解析器一定会自动在后面填充分号(;),所以第二个函数报错,第二段代码等价于:
    function foo2() {
        return;  //这里换行
        {
            bar: "hello"
        };
    }

6.神马是 NaN,它的类型是神马?怎么测试一个值是否等于 NaN?

NaN 是 Not a Number 的缩写,JavaScript 的一种特殊数值,可以通过 isNaN(param) 来判断一个值是否是 NaN:
console.log(isNaN(NaN));       // true
console.log(isNaN(123));       // false
console.log(isNaN("1111"));    // false

console.log(isNaN("1asd"));    // true

console.log(isNaN("asdaa222"));//  true

console.log(isNaN("'ssss'"));  //  true

console.log(isNaN==isNaN);     //  true

console.log(isNaN===isNaN);    //  true

console.log(Object.prototype.toString.apply(isNaN));
//  [object Function]

console.log(Object.prototype.toString.call(isNaN));
 // [object Function]

console.log(typeof isNaN)  // function
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值