JS 基础知识1

  • 数据类型
  • 原型链
  • 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可以


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')

1664424342748.png
1664424973675.png

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


image.png

箭头函数没有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、立即执行函数是什么?

概念题:
是什么?
声明一个匿名函数,然后立即执行它。这种做法就是立即执行函数。
怎么做?

image.png

注意第一个例子立即执行函数要加;不然返回值为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

7、JS如何实现类?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容