前端与javascript | 青训营笔记

16 阅读2分钟

这是我参与青训营笔记创作活动的第二天

原型与原型链相关

let obj={}
log(obj.__proto__)
log(obj.prototype)
log(Object.prototype)

实例的隐式原型(proto)== 构造函数的显式原型(prototype)

宇宙的尽头(Object.prototype.__proto === null)

最重要的可能就是上面这两点了

const obj={}
obj.__proto__ === Object.prototype

Object.__proto__ === Function.prototype
//function的prototype本质也是对象,是通过Object实例化实现的
Function.prototype.__proto__ === Object.prototype
//宇宙的尽头
Object.prototype.__proto === null

New 操作符的背后

  • 创建一个新的空对象
  • 让新的空对象的隐式原型(proto)指向构造函数的原型对象(prototype)
  • 让新的空对象的作用域指向构造函数的作用域,也就是改变构造函数的 this 指向新的空对象
  • 执行构造函数并返回结果,判断返回的结果如果是对象则返回,否则返回新创建的对象

一道js题

学习js途中遇到的一道很经典的题目,困扰了我一段时间

考察知识点:this,变量函数提升,new,运算符优先级

话不多说,上题:

function Foo(){
	getName = function(){
		console.log(1)
	}
	return this
}
Foo.getName = function(){
	console.log(2)
}
Foo.prototype.getName = function(){
	console.log(3)
}
var getName = function(){
	console.log(4)
}
function getName(){
	console.log(5)
}
getName()
Foo.getName()
Foo().getName()
getName()
new Foo().getName()
new (Foo.getName)() 

答案:

解析:

第一个考察变量与函数提升优先级,函数大于变量提升, 所以为 4

第二个没啥好说的

第三个 Foo() 执行 ,第一句是一个赋值语句,没有找到 getName, 于是到外层作用域查找,找到了 var 声明的 getName,于是替换了 然后返回 this , 此时 Foo() 函数是 window 调用的,于是 this = window, 再执行 window.getName() 此时getName被替换了, 所以输出为 1

第四个 也是 1

第五个 括号优先级大于new ,所以先执行 Foo() 返回的this 代表实例化对象,然后调用实例化对象的getName方法,没有找到,于是顺着原型链 ,找到了getName(),返回 3

此处插一个小知识点,如下

构造函数的返回值

在传统语言中,构造函数不应该有返回值,实际执行的返回值就是此构造函数的实例化对象。

而在js中构造函数可以有返回值也可以没有。

1、没有返回值则按照其他语言一样返回实例化对象。

2、若有返回值则检查其返回值是否为引用类型。如果是非引用类型,如基本类型(string,number,boolean,null,undefined)则与无返回值相同,实际返回其实例化对象。

3、若返回值是引用类型,则实际返回值为这个引用类型。

第六个 foo.getName 其实就是一个函数,也就是将console.log(2)这个函数作为构造函数,构造函数在执行时会执行构造函数中的代码,所以返回 2 (具体的 new 操作过程中发生了什么,可以看这篇文章:www.cnblogs.com/echolun/p/1…