JavaScript-prototype

先了解一点JavaScript知识(复制粘贴大法)

  1. ECMAScript is based on several originating technologies, the most well-known being JavaScript (Netscape) and JScript (Microsoft).

  2. ECMAScript is object-based: basic language and host facilities are provided by objects, and an ECMAScript program is a cluster of communicating objects. In ECMAScript, an object is a collection of zero or more properties each with attributes that determine how each property can be used—for example, when the Writable attribute for a property is set to false, any attempt by executed ECMAScript code to assign a different value to the property fails. Properties are containers that hold other objects, primitive values, or functions. A primitive value is a member of one of the following built-in types: Undefined, Null, Boolean, Number, String, and Symbol; an object is a member of the built-in type Object; and a function is a callable object. A function that is associated with an object via a property is called a method.

  3. Even though ECMAScript includes syntax for class definitions, ECMAScript objects are not fundamentally class-based such as those in C++, Smalltalk, or Java. Instead objects may be created in various ways including via a literal notation or via constructors which create objects and then execute code that initializes all or part of them by assigning initial values to their properties. Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties. Objects are created by using constructors in new expressions; for example, new Date(2009, 11) creates a new Date object. Invoking a constructor without using new has consequences that depend on the constructor. For example, Date() produces a string representation of the current date and time rather than an object.

Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” property. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain. When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name. In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.

  1. ECMAScript Language Type
  • The Undefined Type
  • The Null Type
  • The Boolean Type
  • The String Type
  • The Symbol Type
  • The Number Type
  • The Object Type
    数据类型就这七种(早些时候没有 The Symbol Type,未来会不会加入其他Type?我说错了你可以来打我)。对我们来说,重要的是值(Value),比如undefined,null,true,false,”美女”,{老婆:false},function 老婆 (many){return “2B”;}。

举个栗子,var b = "呵呵"; var bb = new String("别BB");

  • b,它的值 "呵呵",是字符串,The String Type。
  • bb,它的值 {...},是对象,The Object Type;但是呢,bb[0]=”别”,bb[1]=”B”,bb[2]=”B”,也就是说bb中的”别BB”是字符串,The String Type。
  • new String中的String仅仅是constructor,和The String Type中的String没毛线关系。
  • 类型转换不小心就会发生,自己得注意到底是什么Type。

再说prototype

网上有张图,很牛逼。 官方网址,里面有大图,可以打印出来。

为毛是这种关系? typeof Function.prototype === "function",这又是为毛?

假定我们就运行下面的代码

prototype就用这位前辈的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Foo() {
this.value = 42;
}

Foo.prototype = {
method: function() {}
};

function Bar() {}

Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';

Bar.prototype.constructor = Bar;

var test = new Bar();
  1. 我们处于 global-EC,初始化。

图片虽然很丑陋,好歹也是自己画的。有些地方不准确,有些地方有错误。不要在意这些细节(当然也省略了巨多的细节),内存中的对象大概就是这种模样。一般JS引擎都提供了__proto__供大家调试代码。而这形成了一个链条,人称原型链。干啥用的?继承。也就是复用代码。

  1. 现在来执行代码。
  • 那就是执行第5行,改变了Foo.prototype。 没名字那儿,我就用???代替了。
  • 再来执行第11行代码。这个new先不考虑,这里会调用特定的方法,当然这里也会产生新的EC,并在在里面生成一个新的对象,这个新对象{value: 42, __proto__: Foo.prototype}。当退出这个EC后,我们Bar.prototype之前的样子应该是{constructor: Bar, __proto__: Object.prototype},不过现在换人了;就像第5行那里一样,Foo.prototype的值也换人了。
  • 接着执行第12行代码。
  • 接着执行第14行代码。
  • 最后执行第16行代码。就像第11行,我们还是不考虑new,不考虑这个新的EC。现在test就不是undefined了。

此时,test.foo, test.value, test.constructor, test.method, test.hasOwnProperty通过原型链都可以使用了。

上篇文章abstract中,那时候我说 this 不重要。this是一个keyword,在new Foo()中的this和那时候的this用法完全不一样,这里的thisFunction.prototype.call, Function.prototype.apply中一样,都是特别提供的。

我们上面的图片,简化,只画出了global-EC,其他EC没画出来。不过可以看出来,如果我在其他EC中定义一个函数,返回此函数。然后我用一个变量接受,那么,虽然此时那个EC已经不存在,但是由于我用变量引用了此函数值,那么内存中还是存在这个函数对象,通过它的[[Scopes]],也能访问消失的EC中定义的名字(比如变量名字,函数名字)。很多时候我们用的

1
(function shit(shit){...}(window))

它运行产生一个EC,完了退出,但是我们如果在外环境引用了返回值(比如传window进去,把新属性挂在上面),那么虽然此EC已退出,但是其中涉及的对象还是存在于内存中。