「这是我参与2022首次更文挑战的第31天,活动详情查看:2022首次更文挑战」
1 instanceof 的用法
注意 instanceof是二元操作符即可,返回值是一个布尔类型。
只要是在实例的原型链上能找到的构造函数,都会返回true。原始值一定会返回false,BigInt Symbol不例外
instance instanceof constructor
所有对象的原型链都止于 Object.prototype.___ptoto__。
2 箭头函数为什么不能用作构造函数
我们已经知道,任何正常的函数,其实都能用作构函数,只要new 一下。
new 的时候会改变函数内部this指向,指向新创建的对象。
而箭头函数的特性就是,声明的时候其内部this 已经确定为从外部继承。那么,箭头函数的this 改不了吗? 试了一下 call(this,...args) apply(this, args),果然没有效果。
所以简单回答就是箭头函数固化了this,深入一点就是,因为箭头函数没有[[Construct]]这个内部槽, 没有prototype这个属性。
不用new ,构造函数在实例化时,有一步操作就是把新对象的[[prototype]]特性赋值为函数的 [[constructor]]特性, 但是箭头函数它没有prototype这个属性,也就是没有能力给新对象一个厂家标识,而构造函数和普通工厂函数的区别就在于增加了标识,箭头函数办不到这点,自然就不能作为构造函数。
3 如果一个构造函数,bind了一个对象,用这个构造函数创建出的实例会继承这个对象的属性吗?
一般不会, 创建对象时this会指向新实例,新实例又只会从原型上继承属性,新的实例的原型就是函数的原型对象, 没变。 除非。。。。没有除非。除非,函数实现逻辑是返回一个非空对象,然后再动一些手脚。
优先级:new 绑定 > 显示绑定 > 隐式绑定 > 默认绑定
this 的判断顺序:
new 绑定: 函数是否在 new 中调用?如果是的话 this 绑定的是新创建的对象;
显式绑定: 函数是否是通过 bind、call、apply 调用?如果是的话,this 绑定的是指定的对象;
隐式绑定: 函数是否在某个上下文对象中调用?如果是的话,this 绑定的是那个上下文对象;
如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到全局对象。
4 js 上下文
执行上下文是代码运行的环境,代码是运行在上下文中的。
有三种情况会创建新的上下文,并把上下文推入执行栈中,一般来说栈底永远是全局上下文或空
- 全局上下文为运行代码主体而创建,也就是说一有代码运行就会创建全局上下文,这就是大环境。
- 每个函数在调用时会创建一个新的上下文,也就是我们常说的当前上下文。构造函数也是函数
- 使用eval也会创建一个的执行上文。
一个上下文的生命周期就是代码从开始到结束,不妨把全局代码当做都在main函数内执行,这样就都是函数执行会生成新的上下文。函数执行完毕则弹栈对应的上下文。然后继续上一个未销毁的上下文。就是栈的嵌套。
5 js 作用域链
查找变量的过程就是作用域链。当我们要访问变量 a时,会先在当前作用域查找,可能是函数作用域,也可能是块级。粗暴一点(不管var)来看就是找最近的大括号就行了。 如果这层大括号的作用域没有声明这个变量,就会调出这个大括号,往外继续找,外层没有,再继续跳一层,直到找到,或者到顶(全局作用域)。
换言之,一旦在某个作用域找到了,就不会再往上了。这个链也是单向链表, 任何作用域都是往外查找的,这就外部不能访问内部。函数的闭包其实也就是这样的。
6 window.name的作用
默认空字符,窗口的名字主要用于为超链接和表单设置目标.可用作打开新窗口时target的值。也有人奇思妙想用作同一窗口不同页面的通信,不过有localstorage sessionstorage
7 window.window
自引用, 也就是说这个属性指向window对象本身
将 window 属性指向该window对象本身的目的,是为了更容易引用全局对象。不然,就得在最开始写代码的时候进行手动赋值:var window = this; 。但我觉得这个说法不能令我信服,作用域链不就是干这个的吗。
还是说就是要隐藏全局对象window,让我们只访问它的属性而不是它本身。我好像明白了什么,作为全局上下文window实际上没有标识符,因为它已经是最顶层,所有变量 的名都是它取的,谁给它取名呢,如果没有window这个属性,实际上确实只能用this拿到全局对象。
8 闭包及其产生
闭包是函数和对其周围的词法环境捆绑在一起,包含函数执行的一切依赖。 当有函数被创建(声明)就产生了闭包。不需调用。
我不认可红宝书所说只有函数内部使用外部作用域的变量才产生闭包,这种情况下,闭包才值得关注罢了。
9 词法作用域 块级作用域 作用域链 静态动态作用域
词法作用域 根据变量声明的位置来分析,什么作用域能访问到这个变量, 也就是在何处可用。
词法作用域就是静态作用域, 一旦一个变量被声明,其词法作用域也就确定了。编码(编译)之后就已经确定
块级作用域 , 简单的说块级作用域就是{}所包裹的且使用了let const 的变量的作用域,以前就只有函数作用域(全局也可认为是一个最大的函数作用域)。 和函数作用域的区别就是,用let const声明的变量不会挂当前函数作用域的上下文,且必须初始化(赋值)才能访问,不能重复声明。全局作用域下的块级也不会给全局对象添加属性
动态作用域就是函数执行时的作用域(还是把全局当成一个最外面的函数),动态是因为在执行时才确定。执行时动态的就是this,执行的时候才知道this当前执行上下文
虽然es6好像对作用域链有什么规定,但是我理解就是当前从当前(执行)作用域出发,能访问到的作用域,就是作用域链,查找过程是链式的,也就是单向链表。
10 闭包的应用场景
闭包的特性就是静态作用域链, 外部不能访问内部, 内部可以访问外部。
主要就是两种,一是所谓的私有化,不想让外部能访问。
二就是函数工厂,定义一类函数,大体逻辑相同,但是某个变量(也可以是函数)会变化,但是定义的时候就确定了, 这个时候就是由外层函数传入所需的变量,然后定义函数,返回这个函数。
闭包引用了外部变量就会导致,外部的变量一直被引用,从而不会被清除,如果有希望不被清除的变量就可以这么干。
柯理化确实用到了闭包,但是我感觉这不算它的应用场景吧。 毕竟创建一个函数其实就有闭包了,高阶函数更不用说了。