JS面试真题 part2
- [6、typeof 与 instanceof 区别](#6、typeof 与 instanceof 区别)
- 7、JavaScript原型,原型链?有什么特点
- 8、说说你对作用域链的理解
- 9、谈谈this对象的理解
- 10、说说new操作符具体干了什么
6、typeof 与 instanceof 区别
自己回答:
typeof
:用来判断数据的类型 假设 s1='字符串' ,则 typeof s1
的值为string
。不过typeof null
的值是object
。因为null是000000,object的是以000开头,这是js设计上的问题。
instanceof
:用来判断某个值是否在他的原型链上,假设 s1=new String('字符串'),则 s1 instanceof String
的值为true,缺点是基础数据需要用new创建出来,s1='字符串',则值为false
标准回答:
typeof
操作符返回一个字符串,表示未经计算的操作数的类型 ,使用方法:typeof operand
、 typeof (operand)
,返回operand的类型
前六个都是基础类型,其中typeof null
返回的是object,这是一个bug。还有除了function,其他的引用类型都是返回object。
instanceof
运算符用于检测构造函数的prototype
属性是否在某个实例对象的原型链上
使用方法:object instanceof constructor
,object
为实例对象,constructor
为构造函数
typeof 与 instanceof 都是判断数据类型的方法,区别如下:
- typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值
- instanceof可以准确的判断复杂引用类型,但是不能正确判断基础数据类型
- typeof也存在弊端,可以判断基础数据类型(null除外),但是引用类型中,除了function类型以外,其他的也无法判断
如果需要通用检测数据类型,可以采用Object.prototype.toString
,返回"[object xxx]"的字符串
实现一个全局通用的数据类型判断方法
使用如下:
7、JavaScript原型,原型链?有什么特点
自己回答:
JavaScript原型 :JavaScript对象的构造函数都有原型,实例对象的构造函数 object().prototype, 实例的隐式__proto__指向这个原型,实例可以通过__proto__访问构造函数的prototype属性,从而继承一些属性和方法。
原型链 :构造函数的prototype属性,也是一个对象,这个对象也有构造函数,也可以指向有构造函数的prototype,就形成了原型链,一个对象可以在原型链上依次向上寻找属性和方法,即可以向原型,原型的原型,原型的原型的原型依次寻找。直到对象是null。
原型和原型链为对象提供了一些可以继承的属性和方法
标准回答:
原型 :每个对象都有一个原型,当试图访问一个对象的属性时,不仅在该对象上找,也会在对象的原型上找,以及对象原型的原型,依次向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
准确的说,这些方法和属性定义在Object的构造器函数上的ptototype属性上,而不是实例对象本身。
函数都有一个属性ptototype,function.ptototype就是我们说的原型 function.ptototype有个属性constructor指向函数function
原型链 :原型对象也有原型,并从中继承方法和属性,一层一层,依此类推,这种关系通常被称为原型链。
对象实例p和它的构造函数person之间会建立一个链接。p. __ proto __ ==person.ptototype
8、说说你对作用域链的理解
自己回答:
作用域链:作用域分为全局作用域和函数作用域。
函数作用域里的对象是活动对象,当最里层的函数作用域没有找到活动对象时,可以向外依次寻找,直到全局作用域
标准回答:
作用域 ,即变量(变量作用域又称上下文)和函数生效(能被访问)的区域或集合。换句话说,作用域决定了代码区块中变量和其他资源的可见性
一般将作用域分为:
- 全局作用域
- 函数作用域
- 块级作用域
全局作用域:任何不在函数中或者大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问
函数作用域:也叫局部作用域,如果一个变量是在函数内部声明的它就在一个函数作用域下面,这些变量只能在函数内部访问,不能在函数外访问。
块级作用域:ES6引入了let和const关键字,和var关键字不同,在大括号中使用let和const声明的变量存在于块级作用域中。在大括号之外不能访问这些变量
词法作用域 ,又叫静态作用域,变量在创建时就被确定了,而非执行阶段确定的,JavaScript遵循的就是词法作用域
作用域链 :当在JavaScript
中使用一个变量的时候,首先JavaScript引擎会尝试在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推,找到该变量或是已经到了全局作用域,如果在全局作用域仍然找不到该变量,就会在全局范围内隐式声明该变量(非严格模式下)或直接报错
9、谈谈this对象的理解
自己回答:
this是函数里的指代对象,指向调用他的人
分为默认调用,隐式调用,call/apply/bind调用
默认调用:普通函数,window对象
隐式调用:实例对象调用
call/apply/bind调用:改变this指向调用
标准答案:
定义 :函数的调用方式决定了this
的值(运行时绑定 ),this
关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象
this
在函数执行过程中,this
一旦确定了,就不可以再更改
绑定规则:
-
默认绑定:全局环境中调用普通函数,函数内部使用this,指向全局对象window(非严格模式),严格模式下报错,this绑定undefined
-
隐式绑定:函数作为某个对象的方法调用,此时this指向上级对象,o.b.fn(),fn里的this指向b
-
new绑定 :通过构建函数
new
关键字生成一个实例对象,此时this
指向这个实例对象
-
显示绑定:call/apply/bind绑定,显示修改this指向
箭头函数
ES6提供的箭头函数,在代码书写(编译时)就确定this指向,箭头函数不能作为构造函数
优先级
new绑定>显示绑定>隐式绑定>默认绑定
10、说说new操作符具体干了什么
自己回答:
new操作符:执行构造函数、改变实例对象的this指向
标准回答:
是什么:new操作符用于创建一个给定构造函数的实例对象
- new通过构造函数创建出来的实例可以访问构造函数中的属性
- new通过构造函数创建出来的实例可以访问构造函数原型链上的属性和方法
如果构造函数有返回值:
返回基础值,和没有返回值时表现一致
如果返回对象,则
new的流程
- 创建了一个新的对象obj
- 将对象与构造函数通过原型链连接起来
- 将构建函数中的this绑定到对象obj上
- 如果构建函数有返回值,如果是对象,则实例对象是返回的对象,如果返回值是基础类型,则忽略
手写new操作符
javascript
function mynew(Func,...args){
//1.创建一个新对象
const obj={}
//2.新对象原型指向构造函数的原型对象
obj.__proto__=Func.prototype
//3.将构造函数的this指向,指向obj,并执行构造函数
let result= Func.apply(obj,args)
//4.根据构造函数执行后的返回结果,确定返回的对象
//如果没有返回值或者返回的值不是对象,则返回新创建的对象,如果返回的是一个对象,则返回该对象
return result intanceof Object?result:obj
}