美文网首页
Nodejs 1:Javascript 基础

Nodejs 1:Javascript 基础

作者: rill_ | 来源:发表于2017-06-29 09:46 被阅读0次

    1. 类型判断

    1.1 类型

    JS有5种简单数据类型(基本数据类型):undefined, null, boolean, number, string;还有一种复杂数据类型:object

    1.2 类型判断方法

    1.2.1 typeof操作符

    typeof操作符返回值:"undefined", "boolean", "number", "string","object","function"
    注:typeof null返回值是"object",特殊值null被认为是一个空对象引用,但是在safari5和chrome7之前,正则表达式调用typeof操作法返回值是"function"

    1.2.2 instanceof

    instanceof 是用来判断 A 是否为 B 的实例对,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。 在这里需要特别注意的是:** instanceof检测的是原型**

    [] instanceof Array; //true
    {} instanceof Object;//true
    new Date() instanceof Date;//true
     
    function Person(){};
    new Person() instanceof Person;
     
    [] instanceof Object; //true
    new Date() instanceof Object;//true
    new Person instanceof Object;//true
    
    Paste_Image.png
    从原型链可以看出,[] 的 proto 直接指向Array.prototype, 间接指向Object.prototype, 所以按照 instanceof 的判断规则,[] 就是Object的实例。当然,类似的new Date()、new Person() 也会形成这样一条原型链,因此,** instanceof 只能用来判断两个对象是否属于原型链的关系, 而不能获取对象的具体类型 **。

    1.2.3 constructor

    JS在函数F的原型上定义了constructor,当F被当作构造函数用来创建对象时,创建的新对象就被标记为了“F” 类型,使得新对象有名有姓,可以追溯。

    Paste_Image.png

    细节问题:
    null和undefined是无效的对象,因此是不会有constructor存在的,这两种类型的数据需要通过typeof来判断。
    JS对象的constructor是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype后,原有的constructor会丢失,constructor会默认为Object

    1.2.4 Object.prototype.toString

    toString是Object原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,... 基本上所有对象的类型都可以通过这个方法获取到。

    Object.prototype.toString.call('') ;   // [object String]
    Object.prototype.toString.call(1) ;    // [object Number]
    Object.prototype.toString.call(true) ; // [object Boolean]
    Object.prototype.toString.call(undefined) ; // [object Undefined]
    Object.prototype.toString.call(null) ; // [object Null]
    Object.prototype.toString.call(new Function()) ; // [object Function]
    Object.prototype.toString.call(new Date()) ; // [object Date]
    Object.prototype.toString.call([]) ; // [object Array]
    Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
    Object.prototype.toString.call(new Error()) ; // [object Error]
    Object.prototype.toString.call(document) ; // [object HTMLDocument]
    Object.prototype.toString.call(window) ; //[object global] window是全局对象global的引用
    

    需要注意的是,必须通过Object.prototype.toString.call来获取,而不能直接 new Date().toString(), 从原型链的角度讲,所有对象的原型链最终都指向了Object, 按照JS变量查找规则,其他对象应该也可以直接访问到Object的toString方法,而事实上,大部分的对象都实现了自身的toString方法,这样就可能会导致Object的toString被终止查找,因此要用call来强制执行Object的toString方法。

    2 作用域

    2.1 es6 var, let, const

    在JS函数中的var声明,其作用域是函数体的全部;
    let与var一样,也可以用来声明变量,但它有着更好的作用域规则。let声明的变量拥有块级作用域,let声明的全局变量不是全局对象的属性。用let重定义变量会抛出一个语法错误(SyntaxError)。
    const声明的变量与let声明的变量类似,它们的不同之处在于,const声明的变量只可以在声明时赋值,不可随意修改,否则会导致SyntaxError(语法错误)。

    2.2 函数闭包

    Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。另一方面,在函数外部自然无法读取函数内的局部变量。出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

           function f1(){
        var n=999;
        function f2(){
          alert(n); 
        }
        return f2;
      }
      var result=f1();
      result(); // 999
    

    f2函数,就是闭包。闭包就是能够读取其他函数内部变量的函数。
    所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
    1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
    2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

    3 引用传递

    3.1 引用类型

    (1)值类型:数值、布尔值、null、undefined。
    (2)引用类型:对象、数组、函数。

    3.2 引用传递, 值传递

    简单点说, 对象是引用传递, 基础类型是值传递, 通过将基础类型包装 (boxing) 可以以引用的方式传递。3 个特殊的引用类型:Boolean、Number 和String

    3.3 ==与===

    "==="叫做严格运算符,"=="叫做相等运算符。
    a === b 是最简单的。如果 a 和 b 的类型不同,那么一定会返回 false。而 a == b 则要灵活得多。JavaScript 会尝试调整 a 和 b 的类型,例如若 a 为字符串 b 为数字,则将字符串先转化为数字再与 b 比较,等等。这在很多时候简化了程序员的代码量。参考【4】

    [1] == [1]  //false
    [1] === [1] //false
    

    3.4 指针与引用的区别(cpp)

    指针一般指的是某块内存的地址,通过这个地址,我们可以寻址到这块内存;而引用是一个变量的别名

    1. 引用必须被初始化,指针不必。
    2. 引用初始化以后不能被改变,指针可以改变所指的对象。
    3. 不存在指向空值的引用,但是存在指向空值的指针。

    4 内存释放

    4.1 js内存什么时候释放

    引用类型是在没有引用之后, 通过 v8 的 GC 自动回收, 值类型如果是处于闭包的情况下, 要等闭包没有引用才会被 GC 回收, 非闭包的情况下等待 v8 的新生代 (new space) 切换的时候回收.

    4.2 垃圾回收机制

    最常使用的方法叫做"引用计数"(reference counting):语言引擎有一张"引用表",保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放。

    5 ES6 新特性

    推荐阅读阮一峰的 《ECMAScript 6 入门》
    比较简单的会问 let与 var 的区别, 以及 箭头函数与 function的区别等等.深入的话, es6 有太多细节可以深入了. 比如结合 引用 的知识点来询问 const方面的知识. 结合 {}的使用与缺点来谈 Set, Map 等. 比如私有化的问题与 symbol等等.其他像是 闭包是什么?这种问烂了问题已经感觉没必要问了, 取而代之的是询问闭包应用的场景更加合理. 比如说, 如果回答者通常使用闭包实现数据的私有, 那么可以接着问 es6 的一些新特性 (例如 class, symbol) 能否实现私有, 如果能的话那为什么要用闭包? 亦或者是什么闭包中的数据/私有化的数据的内存什么时候释放? 等等.
    ...
    的使用上, 如何实现一个数组的去重 (使用 Set 可以加分).const 定义的 Array 中间元素能否被修改? 如果可以, 那 const 修饰对象有什么意义?

    const 定义的 Array 中间元素能否被修改? 如果可以, 那 const 修饰对象有什么意义?
    

    其中的值可以被修改. 意义上, 主要保护引用不被修改 (如用 Map 等接口对引用的变化很敏感, 使用 const 保护引用始终如一是有意义的), 也适合用在 immutable 的场景.

    参考:

    【1】 [Javascript 基础问题](https://github.com/ruanhaiqiang/node-interview/blob/master/sections/zh-cn/js-basic.md#%E7%B1%BB%E5%9E%8B%E5%88%A4%E6%96%AD
    http://www.cnblogs.com/onepixel/p/5126046.html)
    【2】 [深入浅出ES6(十四):let和const](http://www.infoq.com/cn/articles/es6-in-depth-let-and-const
    https://www.zhihu.com/question/27114726)
    【3】浅谈 javascript 中基本包装类型
    【4】JavaScript 中应该用 "==" 还是 "==="
    【5】JavaScript 内存泄漏教程

    相关文章

      网友评论

          本文标题:Nodejs 1:Javascript 基础

          本文链接:https://www.haomeiwen.com/subject/grgqcxtx.html