zoukankan      html  css  js  c++  java
  • 你不知道的JavaScript(上)this和对象原型(四)原型

    五章 原型

    1、[[ Prototype ]]

    JavaScript 中的对象有一个特殊的 [[Prototype]] 内置属性,其实就是对于其他对象的引用。几乎所有的对象在创建时 [[Prototype]] 属性都会被赋予一个非空的值。

    对于默认的 [[Get]] 操作来说,如果无法在对象本身找到需要的属性,就会继续访问对象
    的 [[Prototype]] 链:

    1 var anotherObject = {
    2 a:2
    3 };
    4 // 创建一个关联到 anotherObject 的对象
    5 var myObject = Object.create( anotherObject );
    6 myObject.a; // 2

    还有另外一种方法,就是使用for..in遍历对象时原理,和查找[[ Prototype ]]链想死,任何可以通过原型链访问到的属性都会被枚举。使用in操作符来检查属性在对象中是否存在也会查找对象的整条原型链(无论属性是否可枚举)

    var anotherObject = {
    a:2
    };
    // 创建一个关联到 anotherObject 的对象
    var myObject = Object.create( anotherObject );
    for (var k in myObject) {
    console.log("found: " + k);
    }
    // found: a
    ("a" in myObject); // true

    2、“构造函数“

    在 JavaScript 中对于“构造函数”最准确的解释是,所有带 new 的函数调用。函数不是构造函数,但是当且仅当使用 new 时,函数调用会变成“构造函数调用”

    1 function NothingSpecial() {
    2 console.log( "Don't mind me!" );
    3 }
    4 var a = new NothingSpecial();
    5 // "Don't mind me!"
    6 a; // {}

    3、原型继承【重点】

    图中由下到上的箭头表明这是委托关联,不是复制操作。

    典型的“原型风格”,例子如下:

     1 function Foo(name) {
     2 this.name = name;
     3 }
     4 Foo.prototype.myName = function() {
     5 return this.name;
     6 };
     7 function Bar(name,label) {
     8 Foo.call( this, name );
     9 this.label = label;
    10 }
    11 // 我们创建了一个新的 Bar.prototype 对象并关联到 Foo.prototype
    12 Bar.prototype = Object.create( Foo.prototype );
    13 // 注意!现在没有 Bar.prototype.constructor 了
    14 // 如果你需要这个属性的话可能需要手动修复一下它
    15 Bar.prototype.myLabel = function() {
    16 return this.label;
    17 };
    18 var a = new Bar( "a", "obj a" );
    19 a.myName(); // "a"
    20 a.myLabel(); // "obj a"

    核心部分就是语句 Bar.prototype = Object.create( Foo.prototype ) 。调用Object.create(..) 会凭空创建一个“新”对象并把新对象内部的 [[Prototype]] 关联到你指定的对象(本例中是 Foo.prototype )。但是 Object.create(..)唯一的缺点就是需要创建一个新对象然后把旧对象抛弃掉,不能直接修改已有的默认对象。

    ES6添加了一个辅助函数Object.setPrototypeOf(..) ,可以用标准并且可靠的方法来修改关联。

    对比一下两种关联的方法

    1 // ES6 之前需要抛弃默认的 Bar.prototype
    2 Bar.ptototype = Object.create( Foo.prototype );
    3 // ES6 开始可以直接修改现有的 Bar.prototype
    4 Object.setPrototypeOf( Bar.prototype, Foo.prototype );

    4、检查“类”的关系

    寻找对象a委托的对象,也就是检查一个实例(js中的对象)的继承祖先(js中的委托关联)被称为内省(或者反射)

    例子

    1 function Foo() {
    2 // ...
    3 }
    4 Foo.prototype.blah = ...;
    5 var a = new Foo();

    方法一  (instanceof)

    instanceof 操作符的左操作数是一个普通的对象,右操作数是一个函数。 instanceof 回答的问题是:在 a 的整条 [[Prototype]] 链中是否有指向 Foo.prototype 的对象?可是,这个方法只能处理对象( a )和函数(带 .prototype 引用的 Foo )之间的关系。如果你想判断两个对象(比如 a 和 b )之间是否通过 [[Prototype]] 链关联,只用 instanceof无法实现

    a instanceof Foo; // true

    方法二  

    在本例中,我们实际上并不关心(甚至不需要) Foo ,我们只需要一个可以用来判断的对象(本例中是 Foo.prototype )就行。 isPrototypeOf(..) 回答的问题是:在 a 的整条 [[Prototype]] 链中是否出现过 Foo.prototype ?

    Foo.prototype.isPrototypeOf( a ); // true

     5、创建关联

    Object.create() 的polyfill代码。这段 polyfill 代码使用了一个一次性函数 F ,我们通过改写它的 .prototype 属性使其指向想要关联的对象,然后再使用 new F() 来构造一个新对象进行关联。

    1 if (!Object.create) {
    2   Object.create = function(o) {
    3   function F(){}
    4   F.prototype = o;
    5   return new F();
    6   };
    7 }

     第六章 行为委托

     重点:对象关联

     1 Foo = {
     2               init:function(who){
     3                   this.me=who;
     4               },
     5               identify:function(){
     6                   return "i am "+this.me;
     7               }
     8           };
     9           Bar = Object.create(Foo);
    10           Bar.speak = function(){
    11               console.log("hello"+this.identify()+".");
    12           }
    13           var b1 = Object.create(Bar);
    14           b1.init("b1");
    15           var b2 = Object.create(Bar);
    16           b2.init("b2");
    17           b1.speak();
    18           b2.speak();

    ES6 使用更好的对象字面形式的语法和简洁方法

     1 var AuthController = {
     2 errors: [],
     3 checkAuth() {
     4 // ...
     5 },
     6 server(url,data) {
     7 // ...
     8 }
     9 // ...
    10 };
    11 // 现在把 AuthController 关联到 LoginController
    12 Object.setPrototypeOf( AuthController, LoginController );
  • 相关阅读:
    Ubuntu +PHP-fpm + Nginx 访问php界面空白的界面的分析
    Erlang 语言简介
    坐标体系WGS84/GCJ02/BD09
    Linux 系统的启动顺序
    母板页 难点---数据交换
    用户控件(二)--常见4 种路径问题解决:
    XML语言:可扩展的标记语言;
    用户控件(一) ----交换信息
    单选款复选款的选择并操作方法
    生成指定格式的流水号
  • 原文地址:https://www.cnblogs.com/chorkiu/p/10115683.html
Copyright © 2011-2022 走看看