先来看一下js面向对象的写法演进
//面向对象 一
/*
function makePerson(first, last) {
return {
first: first,
last: last
}
}
function personFullName(person) {
return person.first + ' ' + person.last
}
function personFullNameReversed(person) {
return person.last + ', ' + person.first
}
var s = makePerson('Simon', 'Willision')
console.log(personFullName(s))
console.log(personFullNameReversed(s))
*/
//面向对象 二
/*
function makePerson(first, last) {
return {
first: first,
last: last,
fullName: function() {
//this表示调用了当前函数的对象,即谁调用,对象就是谁
console.log(this)
console.log(this.first)
return this.first + ' ' + this.last
},
fullNameReversed: function(){
return this.last + ', ' + this.first
}
}
}
var s = makePerson('Simon', 'Willision')
var fc = s.fullName
fc()
//console.log(s.fullName())
//console.log(s.fullNameReversed())
*/
// 面向对象 三
/*
function Person(first, last) {
this.first = first
this.last = last
this.fullName = function() {
console.log(this)
return this.first + this.last
}
this.fullNameReversed = function() {
return this.last + ' ,' + this.first
}
}
//每次创建对象都会创建两个函数,不好,并且里边还形成了闭包,影响性能
var s = new Person('Simon', 'Willision')
//var fn = s.fullName
//console.log(fn())
console.log(s.fullName())
*/
//面向对象 四, 函数定义太分散不好
/*
function personFullName(){
return this.first + ' ' + this.last
}
function personFullNameReversed() {
return this.last +', ' + this.first
}
function Person(first, last) {
this.first = first
this.last = last
this.fullName = personFullName
this.personFullNameReversed = personFullNameReversed
}
*/
//面向对象 五,使用原型, 终极方案
function Person(first, last) {
this.first = first
this.last = last
}
Person.prototype.fullName = function() {
return this.first + ' ' + this.last
}
Person.prototype.fullNameReversed = function() {
return this.last + ', ' + this.first
}
const myPerson = new Person('jack','fa')
console.log(myPerson)
//原型这个特性功能十分强大,JavaScript 允许你在程序中的任何时候修改原型(prototype)中的一些东西,
//也就是说你可以在运行时(runtime)给已存在的对象添加额外的方法,因此javascript是动态语言,这是非常灵活的
js作用域链
如果一个变量在当前作用域下找不到,那就找"父级"作用域,如果父级也没呢?再一层一层向上寻找,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是 作用域链 。
注意:刚才的"父级"打引号了,其实这种说法不严谨,其实寻找变量是要到创建这个函数的那个域去找,在创建它的作用域中取值,这里强调的是"创建",而不是"调用"
js作域在ES6之前只有全局和函数级作用域,没有块级作用域
作用域与执行上下文(scope and context)
JavaScript 属于解释型语言,JavaScript 的执行分为:解释和执行两个阶段,这两个阶段所做的事并不一样:
解释阶段:
- 词法分析
- 语法分析
- 作用域规则确定
执行阶段:
- 创建执行上下文
- 执行函数代码
- 垃圾回收
JavaScript 解释阶段便会确定作用域规则,因此作用域在函数定义时就已经确定了,而不是在函数调用时确定,但是执行上下文是函数执行之前创建的。执行上下文最明显的就是 this 的指向是执行时确定的。而作用域访问的变量是编写代码的结构确定的。
执行上下文(context)在运行时确定,随时可能改变;作用域(scope)在定义时就确定,并且不会改变。
一个作用域下可能包含若干个上下文环境。有可能从来没有过上下文环境(函数从来就没有被调用过);有可能有过,现在函数被调用完毕后,上下文环境被销毁了;有可能同时存在一个或多个(闭包)。同一个作用域下,不同的调用(比如使用call/apply/bind)会产生不同的执行上下文环境,继而产生不同的变量的值。
本文由 dealdot <dealdot#163.com> 创作, Full Stack Developer @ DeepBlue
本文最后编辑时间为: Apr 19, 2021 at 16:03 pm
转载请注明来源