美文网首页JavaScript
| 从Array.prototype.slice.call()

| 从Array.prototype.slice.call()

作者: Hemingway_AT | 来源:发表于2019-08-11 23:59 被阅读0次

    最近在翻阅工具书,在基础温习章节,看到了一个比较长的方法调用。为巩固知识,提笔一记吧。目录如下:

    • prototype
    • slice
    • call

    一、prototype

    prototype是Function的属性,常见的Object、Array等都是函数,确切地说是构造函数。

    常见函数的类型.png
    Function.prototype 属性存储了 [Function]的原型对象。[Function]对象继承自 Function.prototype。由此,“JavaScript基于原型”传唱至今。
    函数的prototype属性.png
    细心的你可以从上图中看到:prototype对象中包含一个constructor的键名。通过点语法,Object.prototype.constructor的返回值和Object等同。
    console.log(Object.prototype.constructor === Object);
    // expected output: "true"
    

    到这里,自然要搬出来另一个家伙:__proto__。所有对象都有这个属性,它通过构造函数指向原型对象。

    对象的__proto__属性.png
    但是,Object.prototype.__proto__是不被鼓励的。

    已废弃
    该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。

    警告: 通过现代浏览器的操作属性的便利性,可以改变一个对象的 [[Prototype]] 属性, 这种行为在每一个JavaScript引擎和浏览器中都是一个非常慢且影响性能的操作,使用这种方式来改变和继承属性是对性能影响非常严重的,并且性能消耗的时间也不是简单的花费在 obj.__proto__ = ... 语句上, 它还会影响到所有继承来自该 [[Prototype]] 的对象,如果你关心性能,你就不应该在一个对象中修改它的 [[Prototype]]。相反, 创建一个新的且可以继承 [[Prototype]] 的对象,推荐使用 Object.create()

    警告:Object.prototype.__proto__ 已被大多数浏览器厂商所支持的今天,其存在和确切行为仅在ECMAScript 2015规范中被标准化为传统功能,以确保Web浏览器的兼容性。为了更好的支持,建议只使用 Object.getPrototypeOf()

    Object.prototype__proto__ 属性是一个访问器属性(一个getter函数和一个setter函数), 暴露了通过它访问的对象的内部[[Prototype]] (一个对象或 null)。
    使用__proto__是有争议的,也不鼓励使用它。因为它从来没有被包括在EcmaScript语言规范中,但是现代浏览器都实现了它。__proto__属性已在ECMAScript 6语言规范中标准化,用于确保Web浏览器的兼容性,因此它未来将被支持。它已被不推荐使用, 现在更推荐使用Object.getPrototypeOf/Reflect.getPrototypeOfObject.setPrototypeOf/Reflect.setPrototypeOf(尽管如此,设置对象的[[Prototype]]是一个缓慢的操作,如果性能是一个问题,应该避免)。

    上面的引用提到了一个性能的问题,对于要拓展一个对象,请不要随意修改其原型,使用Object.create()则是更优的选择,demo如下:

    const person = {
      isHuman: false,
      printIntroduction: function () {
        console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
      }
    };
    
    const me = Object.create(person);
    
    me.name = "Matthew"; // "name" is a property set on "me", but not on "person"
    me.isHuman = true; // inherited properties can be overwritten
    
    me.printIntroduction();
    // expected output: "My name is Matthew. Am I human? true"
    

    二、slice

    slice是Array实例具有的方法,实例则基于原型。slice() 方法可从已有的数组中返回选定的元素。用法参考:W3C

    slice原生函数.png

    三、call

    call指的是Function.prototype.call()。call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数,与之类似的函数是Function.prototype.apply()。两者区别就是:call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。还有一个并列的函数叫Function.prototype.bind(),它则会创建一个新的函数;在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。

    /** 构造函数 */
    function Product(name, price) {
      this.name = name;
      this.price = price;
    }
    
    /** 扩展的构造函数 */
    function Food(name, price) {
      Product.call(this, name, price);
      this.category = 'food';
      this.getCalorie = function(){
        return this.value;
      }
    }
    
    var food = new Food('cheese', 5);
    console.log(food.name + ' is ' + food.price);
    // expected output: "cheese is 5"
    
    var globalArr = ['milk', 8];
    Product.apply(this, globalArr);
    
    console.log(window.name + ' is ' + window.price);
    // expected output: "milk is 8"
    
    var milkCalorie = {
      value: 100
    };
    
    console.log(new Food().getCalorie());
    // expected output: "undefined"
    console.log(new Food().getCalorie.bind(milkCalorie)());
    // expected output: "100"
    

    四、 回到标题

    使用Array.prototype.slice.call()变个魔法,将“类似数组的对象”变成真正的数组。

    image.png
    同样地,一个可以替代字符串split方法的函数出现了:
    console.log('future'.split(''))
    // expected output: Array ["f", "u", "t", "u", "r", "e"]
    
    console.log(Array.prototype.slice.call('future'))
    // expected output: Array ["f", "u", "t", "u", "r", "e"]
    

    (完)

    相关文章

      网友评论

        本文标题:| 从Array.prototype.slice.call()

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