美文网首页
你不知道的JavaScript上卷2

你不知道的JavaScript上卷2

作者: Doter | 来源:发表于2017-09-11 16:26 被阅读0次

    1.this

    this 是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调
    用时的各种条件。this 的绑定只取决于函数的调用方式。

    当一个函数被调用时,会创建一个活动记录(有时候也称为执行上下文)。这个记录会包
    含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this 就是记录的其中一个属性,会在函数执行的过程中用到。

    function identify() {
        return this.name.toUpperCase();
    }
    function speak() {
        var greeting = "Hello, I'm " + identify.call( this );
        console.log( greeting );
    }
    var me = {
        name: "Kyle"
    };
    var you = {
        name: "Reader"
    };
    identify.call( me ); // KYLE
    identify.call( you ); // READER
    speak.call( me ); // Hello, 我是 KYLE
    speak.call( you ); // Hello, 我是 READER
    

    2.this的指向

    指向所在方法的调用者

    function foo() {
        console.log( this.a );
    }
    var obj2 = {
        a: 42,
        foo: foo
    };
    var obj1 = {
        a: 2,
        obj2: obj2
    };
    obj1.obj2.foo(); // 42
    

    显示绑定this

    function foo() {
        console.log( this.a );
    }
    var obj={
        a:1
    }
    foo.call(obj)// 1
    

    显式绑定优先级大于隐式

    function foo() {
    console.log( this.a );
    }
    var obj1 = {
    a: 2,
    foo: foo
    };
    var obj2 = {
    a: 3,
    foo: foo
    };
    obj1.foo(); // 2
    obj2.foo(); // 3
    obj1.foo.call( obj2 ); // 3
    obj2.foo.call( obj1 ); // 2
    

    如果要判断一个运行中函数的 this 绑定,就需要找到这个函数的直接调用位置。找到之后
    就可以顺序应用下面这四条规则来判断 this 的绑定对象。

    1. 由 new 调用?绑定到新创建的对象。
    2. 由 call 或者 apply(或者 bind)调用?绑定到指定的对象。
    3. 由上下文对象调用?绑定到那个上下文对象。
    4. 默认:在严格模式下绑定到 undefined,否则绑定到全局对象。

    3.绑定例外

    1. 将null,undefined传入做绑定对象,这些值在调用是会忽略,实际应用默认绑定规则。

    4.对象

    1. 内置对象:
      • String
      • Number
      • Boolean
      • Object
      • Function
      • Array
      • Date
      • RegExp
      • Error
        注意:
    var strPrimitive = "I am a string";
    typeof strPrimitive; // "string"
    strPrimitive instanceof String; // false
    var strObject = new String( "I am a string" );
    typeof strObject; // "object"
    strObject instanceof String; // true
    // 检查 sub-type 对象
    Object.prototype.toString.call( strObject ); // [object String]
    

    strP属于文字形式,strO属于构造形式,在对strP进行操作时,如获取长度等等,引擎会自动将strP转换为object,进行处理。
    null和undefined只有构造形式,而Date只有文字形式。
    Object,Array,Function,RegExp无论以文字形式和构造形式创建都属于对象。

    对象的深浅copy

    浅复制,就是将源对象的值传递过去,如果出现引用,会将引用传递过去.
    常见的json复制是:

    var newObj = JSON.parse( JSON.stringify( someObj ) );
    

    在Es6中可以使用 Object.assign(..)实现浅copy

    属性描述

    writable: true, //可修改
    configurable: true, //可配置
    enumerable: true //可枚举
    可以使用 defineProperty(..)修改属性描述

    不变性

    1.对象的属性使用 writable:false 和 configurable:false 就行。
    2.禁止扩展:

    var myObject = {
    a:2
    };
    Object.preventExtensions( myObject );
    myObject.b = 3;
    myObject.b; // undefined
    

    3.密封 Object.seal(..)
    实际上会在一个现有对象上调用
    Object.preventExtensions(..) 并把所有现有属性标记为 configurable:false
    4.冻结 Object.freeze(..)
    这个方法实际上会在一个现有对象上调用
    Object.seal(..) 并把所有“数据访问”属性标记为 writable:false

    [[Get]]

    myObject.a 在属性访问中,实际是实现了[[Get]]操作,会先在对象的属性中查找,没找到将会遍历可能存在的[[prototype]]链中查找

    [[Put]]

    当存在属性时:

    1. 属性是否是访问描述符(参见 3.3.9 节)?如果是并且存在 setter 就调用 setter。
    2. 属性的数据描述符中 writable 是否是 false ?如果是,在非严格模式下静默失败,在
      严格模式下抛出 TypeError 异常。
    3. 如果都不是,将该值设置为属性的值。
      当不存在属性时:待补充。
    混合对象“类”
    显式混入
    // 非常简单的 mixin(..) 例子 :
    function mixin( sourceObj, targetObj ) {
      for (var key in sourceObj) {
        // 只会在不存在的情况下复制
        if (!(key in targetObj)) {
          targetObj[key] = sourceObj[key];
        }
      }
      return targetObj;
    }
    var Vehicle = {
      engines: 1,
      ignition: function() {
        console.log( "Turning on my engine." );
      },
      drive: function() {
        this.ignition();
        console.log( "Steering and moving forward!" );
      }
    };
    var Car = mixin( Vehicle, {
      wheels: 4,
      drive: function() {
        Vehicle.drive.call( this );
        console.log("Rolling on all " + this.wheels + " wheels!");
      }
    });
    

    由于混入这种方式,两个对象引用的是同一个函数,因此这种复制(或者说混入)实际上并不能完全模拟面向类的语言中的复制。

    寄身继承
    // “传统的 JavaScript 类”Vehicle
    function Vehicle() {
      this.engines = 1;
    }
    Vehicle.prototype.ignition = function() {
      console.log( "Turning on my engine." );
    };
    Vehicle.prototype.drive = function() {
      this.ignition();
      console.log( "Steering and moving forward!" );
    };
    // “寄生类” Car
    function Car() {
    // 首先,car 是一个 Vehicle
    var car = new Vehicle();
    // 接着我们对 car 进行定制
    car.wheels = 4;
    // 保存到 Vehicle::drive() 的特殊引用
    var vehDrive = car.drive;
    // 重写 Vehicle::drive()
    car.drive = function() {
      vehDrive.call( this );
      console.log("Rolling on all " + this.wheels + " wheels!");
      return car;
    }
    var myCar = new Car();
    myCar.drive();
    

    注意在 var car=new Car()时,会生成新对象并丢弃,所以使用时可以不用new。

    隐式混入
    var Something = {
      cool: function() {
        this.greeting = "Hello World";
        this.count = this.count ? this.count + 1 : 1;
      }
    };
    Something.cool();
    Something.greeting; // "Hello World"
    Something.count; // 1
    var Another = {
      cool: function() {
      // 隐式把 Something 混入 Another
      Something.cool.call( this );
      }
    };
    Another.cool();
    Another.greeting; // "Hello World"
    Another.count; // 1 (count 不是共享状态)
    

    相关文章

      网友评论

          本文标题:你不知道的JavaScript上卷2

          本文链接:https://www.haomeiwen.com/subject/vgsfsxtx.html