Skip to content
This repository has been archived by the owner on Jun 2, 2022. It is now read-only.

Javascript Core #6

Open
ivanberry opened this issue Mar 4, 2018 · 0 comments
Open

Javascript Core #6

ivanberry opened this issue Mar 4, 2018 · 0 comments
Assignees

Comments

@ivanberry
Copy link
Owner

JavaScript Core

An object

An object is a collection of properties and has a single prototype object. The prototype may be either an object or the null value.

var foo = {
    x: 10,
    y: 20
};

1f714f17-1961-478b-a360-25fa64ae4ae3

我们定义了一个变量foo,它有两个自己的显性属性和一个内含的属性__proto__,它就是foo原型的索引。

那原型的存在是有什么作用吗?

A prototype chain

原型对象也仅仅只是简单的对象而已,它们同样可能有自己的原型对象。假如一个原型有一个非null的索引,指向它的原型,如此这般,就称为原型链

A prototype chain is a finite chain of objects which is used to implement inheritance and shared properties.

传统面向对象语言是一句类的继承,而ECMAScript中没有类的概念,所以有了基于原型的继承。

var a = {
    x: 10,
    calc: function (v) {
        return this.x + this.y + v; 
    }
};

var b = {
	y: 12,
    __proto__: a
};

var c = {
	y: 20,
    __proto__: a
};

b.calc(10); //32
c.calc(20); //50

正是由于原型链的存在,cb才能访问到a中的calc方法。而这其中的规则也是很简单的:假如一个属性或者方法不能在它本身找到,那就会沿着原型链,直到找到为止,或者返回undefined

a7bacb93-a398-4558-a207-94706aa86c88

如果需要实例化很多个对象,它们拥有相似结构,但是却又有不同的值,这时候我们就需要Constructor了。

Constructor

构造函数不仅仅是新建对象的模式,同时它还自动为新建对象设置了__proto属性。这个原型对象存储在ConstructorFunction.prototype属性中。

通过使用构造函数我们重新之前的例子:

function Foo(y) {
    this.y = y;
}

Foo.prototype.x = 10;
Foo.prototype.calc = function(v) {
    return this.x + this.y = v;
}

var b = new Foo(12);
var c = new Foo(20);

b.calc(12); //32
c.calc(20); //50

console.log(
	b.__proto__ === Foo.prototype, //true
	c.__proto__ === Foo.prototype, //true
	
	b.constructor === Foo, //true
	c.constructor === Foo, //true
	Foo.prototype.constructor === Foo, //true
	
	b.calc === b.__proto__.calc, //true
	c.calc === c.__proto__.calc //true
)

334c2715-f094-42ff-a395-a9ede9326aa5

Execution context stack

ECMAScript规定有三种不同类型的代码:全局代码,函数级代码,eval代码。每一类都有自己的执行上下文。其中全局执行上下文总是只有一个,而每一次函数调用都有函数执行上下文生成和执行相应的代码的过程,eval同样也有eval执行上下文生成和执行相应的代码的过程。一个函数可能会的执行可能会生成有限个执行上下文,从逻辑上说,这形成了一个成为执行上下文栈的栈结构。

激活另一个上下文的上下文称为caller,被激活的上下文称为callee。而callee同样可能是另一个上下文的caller。

当caller激活一个callee时,caller会先挂起自己的运行,并控制权交给callee。callee被推倒栈的顶部,成为运行的执行上下文。callee执行结束后,程序控制权交还给caller,caller上下文继续执行,直到结束。

所有的ECMAScript程序运行时都可以看为执行上下文栈,其中顶部即为当前运行的上下文:

b67d1441-396f-4f57-90d6-37dde5ed6d73

上图就是ECMAScript运行系统对代码执行的管理过程。

执行上下文

我们可以将执行上下文抽象为一个简单的对象。它用一系列的属性(执行状态)来跟踪记录程序执行:

9134d00e-79b2-4b49-abf9-dc137f1be763

变量对象

Variable object is a container of data associated with the execution context. It's a specail object that stores variables and function declarations defined in the context.

变量对象是一个抽象对象。不同类别的上下文,用不同的对象来表示。例如,在全局上下文中,全局变量对象就是全局对象本身,这也就是为什么能直接通过全局对象的属性来访问全局变量的原因。

var foo = 10;

function bar() {}
(function baz() {});

console.log(
	this.foo = foo,
	window.bar === bar
);
console.log(baz); // ReferenceError, 'baz' is not defined.

全局变量对象可以用下图表示:

22933f9a-1f5a-4717-bda8-ecd9c46021a7

Activation object

当一个函数被它的caller调用时,会新建一个激活对象。它包含有形参和一些特殊的参数对象,这个对象就是函数上下文的变量对象。

一个函数的变量对象也仅仅是简单的对象而已,只是除开变量和函数声明外,还储存有形参和arguments

function foo(x, y) {
    var z = 30;
    function bar() {}
    (function baz() {})
}

foo(10, 20);

8f01c9d6-c15d-4674-a863-968570bf9866

Scope chain

A scope chain is a list of objects that are searched for identifiers appear in the code of the context

它的规则和原型链相似:当一个变量不能再自己的作用中找到时,它会沿着父级作用域查询,直到找到为止。

var x = 10;
(function foo() {
    var y = 20;
    (function bar() {
        var z = 30;
        console.log(x + y + z);
    })();
})();

我们可以假设,作用域对象中存在一个__parent的属性,它指向作用域中的下一个对象。另外,我们可以把作用域链简化为一个数组。利用__parent__的概念,我们可以讲以上的代码表示为下图,其中父级变量对象保存在函数的[[Scope]]属性中。

1ded9c71-00df-40fa-a339-98446a0937c7

@ivanberry ivanberry self-assigned this Mar 4, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant