- 数据类型
- 原型链
- this
- new
- 立即执行函数
- 闭包
1、JS数据类型
- 字符串string、数字number、布尔Boolean
- undefined、null(JS两个空)分
别什么时候用:对象为空null 非对象为空undefined(只是一种约定而已) - 大整数bigint、符号symbol(es6新加的)
为什么需要bigint之前的number难道不能用嘛?
因为JSnumber默认是一个双精度浮点数(1--1.0),精度有限。bigint,精度无限。(如果你的数字特别大本身的number无法支持在后面加个n,仅支持整数).
symbol(自己做库用的),比较高级初级一般不用。 - 对象object(数组、函数、日期等这些是对象中的类class不是类型type)
2、原型链是什么?
答:
1、原型链涉及到的概念比较多,我先举例说明一下吧。
- 原型:
假设有一个普通的对象 x = {}, 这个x会有一个隐藏属性 proto,这个属性会指向Object.prototype.
x.proto === Object.prototype.
此时我们说x的原型是Object.prototype,或者说Object.prototype是x的原型。
proto 属性的唯一作用就是用来指向x的原型的。 - 原型链:
假设我们有一个数组对象 a = [],这个a也有一个隐藏属性proto.这个属性会指向Array.prototype.
a.proto === Array.prototype. 同时Array.prototype也有这样一个隐藏属性,Array.prototype.proto指向Object.prototype,这样一来 a就有两层原型,通过隐藏属性proto形成了一个链条。函数Function、Date、Reg(正则)等同理。
这就是原型链。
极简回答:a的原型是b b的原型是c那么就形成了原型链。
2、如何实现一个原型链
之前都是JS引擎提供的 我自己写一个东西 它有原型链行不行。
a = {} b = {}
a.proto = b
b.proto = Object
自己改一下即可,错的,但是对知识点的理解是对的。
1、要用create不可以直接赋值(ES6的方法)
a = Object.create(b),把a的原型置为b
2、new(ES5的方法)
a = new f() f必须是一个构造函数 ,此时a.proto = f.prototype
//详见下面题
3、原型链解决了什么问题?
在没有Class的情况下实现继承。(ES5没有class,ES6之前继承都是通过原型链,继承详见后面)
以a ===> Array.prototype ===>Object.prototype为例
- a是Array的实例,a拥有Array.prototype里的属性
- Arrya继承了Object
- a是Object的间接实例,a拥有Object.prototype里的属性
这样一来,a既拥有Array.prototype里的属性,又拥有Object.prototype里的属性。
原型链优点:简单、优雅
跟class相比不支持私有属性。
如何解决,使用class即可
私有属性:
比如你a.prpto = b
b中有一个函数,c
那就可以a.c
我没有办法让b拥有自己的属性而能不被a使用。
class可以

继承 是什么?
calssB
classA extends B 这就是A继承了B
所以说在技术层面上 继承是两个类的关系。没有对象
var a = new Array(1,2,3)
a.length不是从Array上面继承到的
一个对象拥有其构造函数或类的属性不叫继承,这叫实例化
只能说a是Array实例
a.valueof 是继承 它不是Array提供的而是Object.prototype
Array是a的类 Object.prototype是它的父类,如果这个属性是从它父类那里得到的就是继承。
数组继承了对象。跟a没关系。
https://www.zhihu.com/question/56770432/answer/315342130
3、xxx这段代码的this是什么?
this是什么? this是call的第一个参数
- f1() 等价于f1.call(undefined)
- f1(‘hi’) 等价于f1.call(undefined,'hi')
浏览器一旦发现this是undefined就会把他转成window
左边只是语法糖,所有的调用都是call才是正常形式
就像a = [] 的真正写法是 a = new Array()
obj.child.say()这个函数 叫什么呢?
没有名字,在内存中是按照如下存储的,505就是505只是say存着他的地址。
所以说这个函数和这个对象没有关系,就需要把这个对象传给函数,不然函数如何知道是哪个对象调用它。
假设我把505叫f,f只是存在了say属性中,然后say所在的对象调用的这个函数要传进去。f.call(obj.child)。
obj.child.say() 等价于 obj.child.say.call(obj.child,'hi')


不用看那么多就去找它最后一次执行,看执行的时候的this即可。
所以就是undefined,所以变为window
全局变量var出来的会自动编程window上的属性 所以window.length = 4

箭头函数没有this,看到this就先往外看,没有就是undefined
https://zhuanlan.zhihu.com/p/23804247
(题外话为什么有时候用 call 有时候用apply)
f.call(u,1,2) f.apply(u,[1,2])
假设我 var a = redListFromFile() 读取一个文件 得到一个数组【1,2,...】
如果我要把a传进一个函数
a.call(undefined,a[0],a[1],......)
ES6新语法 a.call(undefined,...a)
但是es6之前也要解决这个问题 所以使用apply
a.apply(undefined,a)
4、new做了什么(记忆题,一般我们不关心只需要知道new的时候创建了一个新的对象)
1、创建一个临时对象
2、绑定原型
3、指定this = 临时对象(不然你访问不到临时对象)
4、执行构造函数(就是士兵添加id,生命)
5、返回临时对象
https://zhuanlan.zhihu.com/p/23987456
Object、Array等的prototype,是为了方便new去给他们创建出来的对象添加共有属性。
Object、Array是用来 给他赋值自身属性的。
就像士兵是用来添加自身属性,士兵.prototype是添加共有属性
5、立即执行函数是什么?
概念题:
是什么?
声明一个匿名函数,然后立即执行它。这种做法就是立即执行函数。
怎么做?

注意第一个例子立即执行函数要加;不然返回值为undefined 会和后面的连起来
解决了什么?
在ES6之前只能通过它来创建局部作用域。
优点:兼容性好
缺点:丑
如何解决丑,使用ES6的block+let语法
!function(){
var a
}()
{
let a//这里不能用var 不然它还是一个全局变量
}
console.log(a)//undefined
6、闭包是什么,如何用?
概念题
是什么?
- 闭包是JS的一种语法特性
- 闭包 = 函数+自由变量
何为自由变量(非全局变量),与之对应的是全局变量,函数本来就可以访问全局变量,如果函数访问全局变量的话,并不能称之为闭包。
大部分语言都支持,语言可以选择支持或不支持闭包,不是什么对象、函数,是一种语法特性。
JS所有函数都是闭包?
函数是对象,不是语法特性。
可以说JS所有函数都支持闭包。
怎么做?
声明一个变量,在函数中访问这个变量。闭包形成了,
let a //全局变量
{
let count //自由变量
function add (){ //访问了外部变量的函数
let a //局部变量
count += 1
}
}
如果count 不是全局变量也不是add函数的局部变量则称之为自由变量。(对于这个函数来说的)
此代码放在非全局环境中,就是闭包。
可以用我上面的写法或者立即执行函数哦
解决了什么问题?(应用场景)
游戏中有一个生命值
{
let lives = 3
window.getLives = function(){return lives}
window.die = ()=>{lives -=1}
window.award = ()=>{lives +=1}
}
window.getLives()
- 隐藏变量(外部访问不到,通过访问器可以)
- 暴露访问器
专业点的说法
- 避免污染全局环境。(因为没有用全局变量而是用的局部变量)
- 提供局部变量的间接访问。
- 维持变量,使其不被垃圾回收
(但是这个变量我一直在用,本身就不会被回收,除非关闭游戏)
面试官如果问就直接写这个最终版本就行了。
立即执行函数写法
var api = function(){
let lives = 3
return{
getLives :()=> lives
die : ()=>{lives -=1}
award : ()=>{lives +=1}
}
}()
api.getLives
api.die // lives -= 1
优点:简单、好用
缺点:闭包使用不当可能造成内存泄漏
(由于旧版本的IE导致的问题)
重点是使用不当而不是闭包,
function test() {
var x = {name: 'x'};
var y = {name: 'y', content: "-----这里很长,有一万三千五百个字符那么长----" }
return function fn() {
return x;
//就是此处return执行后,这个y是不是就应该垃圾回收了,因为我没用。
//由于IE的bug 会导致 你在当前自由变量中用到了x,y就不会被回收
//闭包间接造成的y的内存泄露,理论上应该消失 但是它还占内存
};
}
const myFn = test() // myFn 就是 fn 了
const myX = myFn() // myX 就是 x 了
// 请问,y 会消失吗?
对于一个正常的浏览器来说,y 会在一段时间后自动消失(被垃圾回收器给回收掉)。
但旧版本的 IE 并不是正常的浏览器,所以是 IE 的问题。
怎么解决缺点:
慎用,少用,不用。(我偏要用)
如果问到闭包建议用一下代码和他说:因为这个概念已经对他们根深蒂固了
答题重点是什么?+以下代码,+解决了什么(三个优点)
const add2 = function (){
var count
return function add (){ // 访问了外部变量的函数
count += 1
}
}()
https://zhuanlan.zhihu.com/p/22486908