JavaScript高级用法——原型 & 原型链 / 作用域(一)

目标

  • 掌握JavaScript原型的相关知识点
  • 了解JavaScript作用域的特点

知识要点

  • 原型、原型对象、实例之间的关系
  • 原型链的定义
  • 静态作用域(词法作用域) 和 动态作用域

1、原型

1.1、 关系

  • 什么是原型?
    原型(prototype)是函数的一个特殊属性,即指向原型对象的指针。
    构造函数的原型就是prototype属性,实例对象的原型就是__proto__属性
  • 什么是原型对象?
    原型对象(prototype object)是一个属于其所在函数的空对象,可以添加属性和方法。其自身constructor属性指向其函数。
  • 什么是实例对象?
    实例对象就是构造函数通过new构造出来的新实例

拿以下代码来进行说明:

function Person() {}
const person = new Person()

Person就是构造函数,person就是实例对象

它们之间的 关系 就不多加赘述了,直接如图所示
在这里插入图片描述

console.log(person.__proto__ === Person.prototype) //true
console.log(Person.prototype.constructor === Person) //true
console.log(Object.getPrototypeOf(person) === Person.prototype) //true

console.log(person.constructor === Person) //true
// 解析:person没有constructor属性,要从原型上找这个属性
// 相当于 person.__proto__.constructor === Person.prototype.constructor === Person

1.2、原型链

读取一个对象的属性时,如果该对象没有这个属性时,就会从该对象的原型上查找该属性,如果还查不到,就会从原型的原型上查找,一直找到最顶层为止。

以代码为例:

function Person() {}
Person.prototype.name = 'relex'
const person = new Person()
console.log(person) // 输出{}
console.log(person.name) // 输出name

实例对象的__proto__指向实例原型,那么实例原型的__proto__指向什么呢?
实例原型的__proto__指向的当然是实例原型的原型了,它们之间的关系如下所示:
在这里插入图片描述
其实原型对象就是通过 Object 构造函数生成的,所以Object就是Person的原型,也就是Object是实例对象person的原型的原型。
Object的原型是null,这意味着Object.prototype没有原型,所以查找属性的时候查到Object.prototype就可以停止查找了。其中,蓝色部分就是原型链

总结:当在实例对象中访问某一个属性时,首先会在该对象内部(自身属性)查找,如找不到,则向其__proto__指向的原型中寻找,如仍找不到,则继续向原型中的__proto__指向的上级原型中寻找,直到找到或值为null为止。
原型链的作用:查找对象的属性或方法。

2、作用域

作用域分为以下两种:

  • 静态作用域(词法作用域)
    函数的作用域在函数定义时确定,JavaScript采用的是静态作用域
  • 动态作用域
    函数的作用域在函数调用时确定
var value = 1
function foo() {
	console.log(value)
}
function bar() {
	var value = 2
	foo()
}
bar() // 输出1

因为在JavaScript中,采用的是静态作用域,所以函数的作用域在函数定义的时候就决定了。
在静态作用域中,上述代码在执行foo函数的时候,先从函数内部查找是否有局部变量value,如果没有就根据书写位置,查找上面一层的代码,也就是value 等于1,所以结果输出1;
在动态作用域中,上述代码在执行foo函数的时候,先从函数内部查找是否有局部变量value,如果没有,就从调用函数的作用域,也就是bar函数内部查找value变量,所以结果会打印2

作用域的面试真题:

// case 1
var scope = "global";
function checkscope(){
    var scope = "local";
    function f(){
        return scope;
    }
    return f();
}
checkscope(); // 输出local

// case 2
var scope = "global";
function checkscope(){
    var scope = "local";
    function f(){
        return scope;
    }
    return f;
}
checkscope()(); // 输出local

这两段代码输出的都是local,因为f函数都是在checkscope函数中定义的,所以作用域就是在checkscope函数中,而scope在该函数中有被定义,所以就都返回该值
这两段代码主要区别是在执行上下文有所不同,详细内容见执行上下文的章节

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值