JS面试题
一、基本语法
1.JS中使用typeof能得到的类型
typeof undefined //undefined
typeof 'abc' //String
typeof 123 //Number
typeof true //Boolean 只能判断值类型,不能判断引用类型
typeof {} //Object
typeof [] //Object
typeof null //Object 数组、对象、null统一判断成Object
typeof console.log //function
2.何时使用===和==
if(obj.a == null){
//相当于 obj.a === null || obj.a === undefined
}
以上是jquery推荐用法,其余情况全部用===
3.JS中的内置函数
Object、Array、Boolean、Number、String、Function、Date、RegExp、Error
二、原型与原型链
1.原型规则
所有的引用类型(数组、对象、函数),都有一个__proto__
(隐式原型) 属性,属性值是一个普通的对象。
所有的函数,都有一个prototype
(显式原型) 属性,属性值也是一个普通的对象。
所有的引用类型(数组、对象、函数),__proto__
属性值指向(===)它的构造函数的prototype
属性值。
当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__
(即它的构造函数的prototype
)中寻找。
使用hasOwnProperty()
可以屏蔽来自原型的属性。
2.原型链
f是构造函数FOO的一个实例
f instanceof FOO
的判断逻辑是:f.__proto__
一层一层向上找,看能否对应到FOO.prototype
3.写一个原型链的实例
function Elem(id){
this.elem = doucument.getElementById(id);
}
Elem.prototype.html = function (val){
var elem = this.elem;
if(val){
elem.innerHTML = val;
return this; //链式调用
}
else{
return elem.innerHTML;
}
}
Elem.prototype.on = function (type,fn){
var elem = this.elem;
elem.addEventListener(type,fn);
return this; //链式调用
}
var div1 = new Elem('div1');
div1.html(...).on(... , ...)
该例子可修改DOM内容并相应DOM事件,具有链式调用的功能
4.描述new一个对象的过程
创建一个新对象、this指向这个新对象、执行代码,即对this赋值、返回this
注意: 对象(f.age = 2
)和构造函数(Foo.prototype.age = 2
)都可以添加属性,但对象属性可以根据实例的不同设置不同的值,但原型属性上的值供所有实例使用。
三、作用域和闭包
1.变量提升
在全局作用域中变量定义和函数声明会在全局代码执行前提出来占位。
在函数作用域中变量定义、函数声明、this、arguments会在函数内部代码执行前提出来占位。
注意: 用var声明的变量才存在变量提升,let和const不存在。function fn(){}
是函数声明,var fn = function(){}
是函数表达式,没有变量提升。
由于变量提升的存在,变量和函数在定义前调用并不会报错。
2.this
函数定义时无法判断this的值,只有调用的时候才能判断。
构造函数和对象属性中的this是调用该函数的对象,普通函数的this是window。(this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this指向的是window;当函数被作为某个对象的方法调用时,this就等于那个对象)
call、apply、bind可以改变this的指向。
fn1.call()第一个参数是this指向,其余参数是函数参数。
fn2.apply()第一个参数是this指向,第二个参数是数组,里面存放函数参数。
3.作用域
以var定义的变量没有块级作用域,以let、const定义的变量有块级作用域。
作用域链中按函数定义的位置构成链条(在闭包中很重要)
4.闭包在实际开发中的应用
在上面的例子中,使用闭包可以限制用户权限,用户无法访问
firstLoad()
中传入的参数数组。