这是我参与青训营笔记创作活动的第二天
原型与原型链相关
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…)