当前位置: 首页 > news >正文

JavaScript 基本功--面试宝典

JavaScript数据类型

JavaScript中有哪些基本数据类型

undefinednullnumberstringbooleansymbol(es6中新增)
为啥没有object、array、function?他们都属于复杂的数据类型。看起来有点咬文嚼字。

typeof 操作符对各个数据类型的操作结果

string-------------------------string
number-------------------------number
boolean------------------------boolean
function-----------------------function
undefined----------------------undefined
null---------------------------object (null值表示一个空对象指针)
array--------------------------object
object-------------------------object
因此,有些时候typeof并不能准确的判断某个变量的数据类型。

如何区分null和undefined

通过上边可以看出,使用typeof就可以判断区null和undefined了。
还可以通过null === undefined这种方式来判断。

如何准确的判断一个变量的数据类型

JavaScript 中所有变量都可以当作对象使用,除了 null 和 undefined 两个例外。所以我们可以使用对象原型链上的toString方法来将一个变量转化成字符串,然后区分他们的类型。
Object.prototype.toString.call(*);示例:

Object.prototype.toString.call(null)           //  "[object Null]"
Object.prototype.toString.call(undefined)      //  "[object Undefined]"

*在IE8中两者结果都为 "[object Object]"
因此,我们也可以用这个方法来区分null和undefined

对象创建和使用

创建对象

var obj1 = {x:1,'long name':2};
var obj2 = new Object();
var obj3 = Object.create(obj2);

访问对象属性

obj1.x                // 1
obj1["long name"]     // 2 注意,如果属性名有空格或者中划线什么的就只能使用这种方式了

删除对象属性

delete obj1.x         // 删除对象属性的唯一方法是delete

继承与原型链

前边我们说了,可以认为 JavaScript 中万物皆对象。每个对象都有一个私有 Prototype。它持有一个连接到另一个称为其 prototype 对象(原型对象)的链接。该 prototype 对象又具有一个自己的原型,层层向上直到一个对象的原型为 null。
继承
上边创建对象以及可以看到使用 Object.create 可以实现继承。还有可以使用Object.prototype来实现继承。示例:

var obj = {a:1}
function P(name){    // 构造函数
    this.name = name
}
P.prototype = obj  // 继承obj
var p = new P('wesley');     // 实例对象
p.a                  // 1

其次,我们还可以使用es6中的新语法class等关键字来实现继承。
原型链
原型链的定义复杂拗口,我们可以通过 JavaScript 的非标准但许多浏览器实现的属性__proto__来理解原型链。
对象的__proto__属性是该对象的构造函数的prototype属性。基于上边构造函数继承代码:

console.log(p.__proto__ === P.prototype)                       // true
console.log(P.prototype === obj)                               // true
console.log(P.prototype.__proto__ === Object.prototype)        // true
console.log(Object.prototype.__proto__ === null)               // true

作用域与命名空间

如果了解es6的let用法,那么就应该只要 JavaScript 有块级作用域和函数作用域。简单来说通常我们使用var创建的变量都属于函数作用域。
什么是块级作用域呢?其实可以简单理解为一对花括号包围的代码块的作用范围内。
JavaScript 中没有显式的命名空间定义,这就意味着所有对象都定义在一个全局共享的命名空间下面。
每次引用一个变量,JavaScript 会向上遍历整个作用域直到找到这个变量为止。 如果到达全局作用域但是这个变量仍未找到,则会抛出 ReferenceError 异常。
隐式的全局变量

foo1 = 1;
var foo2 = 2;   // 如果是在函数内部  就是局部变量
let foo3 = 3;   // 如果是在代码块内  就是局部变量

可以通过如下代码的执行结果来理解let和var

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

如果使用let

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

变量声明提升
var 表达式和 function 声明都将会被提升到当前作用域的顶部。要注意的是 let 表达式并不会被提升。
这也正好可以说明如下代码可以正常执行:

test();
function test(){
    console.log(a)
    var a = 5;
}

可以理解为提升后的代码:

function test(){
  var a;  // 此时a为undefined  所以我们打印的时候就是undefined了
  console.log(a)
  a = 5;
}
test();

不使用var申明的变量提升示例:

test();
function test(){
  b = 5
}
console.log(b)
// 5

可以理解为提升后:

var b;  // undefined
(function test(){
  b = 5
})()
console.log(b)

闭包

闭包是 JavaScript 一个非常重要的特性,这意味着当前作用域总是能够访问外部作用域中的变量。
可以理解为访问你本不能够访问到的东西,就是一个闭包。示例:

function Counter(start) {
    var count = start;
    return {
        increment: function() {
            count++;
        },

        get: function() {
            return count;
        }
    }
}

var foo = Counter(4);   // 此时如果我们在外部直接 console.log(count) 是会抛错的
foo.increment();
foo.get(); // 5

这里,Counter 函数返回两个闭包,函数 increment 和函数 get。这两个函数都维持着对 Counter 函数内部作用域的引用。
所以如果需要访问或者说获取Counter中的变量count,只能通过闭包的方式。
关于闭包,有个很经典的例子:

for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}
// 10个10

*想想,为什么。具体可以看:https://segmentfault.com/a/11...
setTimeout 和 setInterval
由于 JavaScript 是异步的,可以使用 setTimeoutsetInterval 来计划执行函数。
*注意: 定时处理不是 ECMAScript 的标准,它们在 DOM (文档对象模型) 被实现。

function foo() {}
var id = setTimeout(foo, 1000); // 返回一个大于零的数字

当 setTimeout 被调用时,它会返回一个 ID 标识并且计划在将来大约 1000 毫秒后调用 foo 函数。 foo 函数只会被执行一次。
所以,通常我们可以认为被setTimeout执行的函数是会被异步执行的。

相关文章:

  • Oracle Number用法
  • Linux下随机10字符病毒的清除
  • wbadmin执行备份命令
  • Oracle Study之案例--通过IPCS查看共享内存之“怪现象”
  • DVDROM驱动不能加载的问题
  • 【驱动】linux设备驱动·扫盲
  • 对Context的重新思考
  • 在RHEL5下构建LAMP网站服务平台之架设Discuz!论坛
  • 依赖倒置原则
  • .net Application的目录
  • React Router
  • 【干货分享】常用端口服务对照表
  • IO操作
  • 【Window OS】解决Win7远程桌面无法全屏的方法
  • Enterprise Library Step By Step系列(十五):配置应用程序块——设计篇
  • [译] 怎样写一个基础的编译器
  • CentOS7简单部署NFS
  • Docker下部署自己的LNMP工作环境
  • Effective Java 笔记(一)
  • JS变量作用域
  • KMP算法及优化
  • markdown编辑器简评
  • springboot_database项目介绍
  • webgl (原生)基础入门指南【一】
  • 大整数乘法-表格法
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 跨域
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 想写好前端,先练好内功
  • 延迟脚本的方式
  • ionic异常记录
  • ​Python 3 新特性:类型注解
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #QT(串口助手-界面)
  • ( 用例图)定义了系统的功能需求,它是从系统的外部看系统功能,并不描述系统内部对功能的具体实现
  • (C++17) std算法之执行策略 execution
  • (DFS + 剪枝)【洛谷P1731】 [NOI1999] 生日蛋糕
  • (MATLAB)第五章-矩阵运算
  • (层次遍历)104. 二叉树的最大深度
  • (附源码)spring boot基于小程序酒店疫情系统 毕业设计 091931
  • (附源码)ssm高校升本考试管理系统 毕业设计 201631
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (七)c52学习之旅-中断
  • (三)docker:Dockerfile构建容器运行jar包
  • (三)终结任务
  • (十) 初识 Docker file
  • (四) Graphivz 颜色选择
  • (一)Neo4j下载安装以及初次使用
  • (转)VC++中ondraw在什么时候调用的
  • *上位机的定义
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .bat批处理(四):路径相关%cd%和%~dp0的区别
  • .form文件_一篇文章学会文件上传