高级js学习

本文深入讲解了JavaScript中的高级特性,包括自定义bind函数、new操作符的实现原理、宏任务与微任务的执行顺序、构造函数与原型链的关系以及继承的实现方式等内容。

一:自定义bind函数

// 第一版 修改this指向,合并参数
Function.prototype.bindFn = function bind(thisArg){
    if(typeof this !== 'function'){ // 这里的this指的就是调用bindFn的方法,这里指的就是original方法,如果this不是一个方法那么直接抛出错误
        throw new TypeError(this + 'must be a function');
    }
    // 存储函数本身
    var self = this;
    // 去除thisArg的其他参数 转成数组,也就是除了替代this的对象之外的参数
    var args = [].slice.call(arguments, 1);
    var bound = function(){
        // bind返回的函数 的参数转成数组
        var boundArgs = [].slice.call(arguments);
        // apply修改this指向,把两个函数的参数合并传给self函数,并执行self函数,返回执行结果
        return self.apply(thisArg, args.concat(boundArgs));
    }
    return bound;
}
// 测试
var obj = {
    name: '轩辕Rowboat',
};
function original(a, b){
    console.log(this.name);
    console.log([a, b]);
}
var bound = original.bindFn(obj, 1);
bound(2); // '轩辕Rowboat', [1, 2]

二:new操作符的作用

  • 创建了一个全新的对象。
  • 这个对象会被执行[[Prototype]](也就是__proto__)链接。
  • 生成的新对象会绑定到函数调用的this
  • 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
  • 如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error),那么new表达式中的函数调用会自动返回这个新的对象。
/**
 * 模拟实现 new 操作符
 * @param  {Function} ctor [构造函数]
 * @return {Object|Function|Regex|Date|Error}      [返回结果]
 */
function newOperator(ctor){
    if(typeof ctor !== 'function'){
      throw 'newOperator function the first param must be a function';
    }
    // ES6 new.target 是指向构造函数
    newOperator.target = ctor;
    // 1.创建一个全新的对象,
    // 2.并且执行[[Prototype]]链接
    // 4.通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的`prototype`对象上。
    var newObj = Object.create(ctor.prototype);
    // ES5 arguments转成数组 当然也可以用ES6 [...arguments], Aarry.from(arguments);
    // 除去ctor构造函数的其余参数,想传参数也只能这样传newOperator(ctor, xx, yy)
    var argsArr = [].slice.call(arguments, 1);
    // 3.生成的新对象会绑定到函数调用的`this`。
    // 获取到ctor函数返回结果
    var ctorReturnResult = ctor.apply(newObj, argsArr);
    // 小结4 中这些类型中合并起来只有Object和Function两种类型 typeof null 也是'object'所以要不等于null,排除null
    var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === 'function';
    if(isObject || isFunction){
        return ctorReturnResult;
    }
    // 5.如果函数没有返回对象类型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),那么`new`表达式中的函数调用会自动返回这个新的对象。
    return newObj;
}

3:作业队列中的执行顺序

在Job queue中的队列分为两种类型:macro-task和microTask。我们举例来看执行顺序的规定,我们设

macro-task队列包含任务:_**a1,a2,a3**_
微任务队列包含任务:_**b1,b2,b3**_

执行顺序为,首先执行marco-task队列开头的任务,也就是_**a1**_任务,执行完毕后,在执行微任务队列里的所有任务,也就是依次执行*** b1,b2,b3 ***,执行完后清空微任务中的任务,接着执行马尔科任务中的第二个任务,依次循环。

了解完完宏任务和微任务两种队列的执行顺序之后,我们接着来看,真实场景下这两种类型的队列里真正包含的任务(我们以节点V8引擎为例),在节点V8中,这两种类型的真实任务顺序如下所示:

宏观任务队列真实包含任务:脚本(主程序代码),setTimeout,setInterval,setImmediate,I / O,UI呈现

micro-task队列真实包含任务:process.nextTick,Promises,Object.observe,MutationObserver

由此我们得到的执行顺序应该为:

script(主程序代码) - > process.nextTick-> Promises ...--> setTimeout - > setInterval - > setImmediate - > I / O - > UI渲染

在ES6中的宏观任务队列又称为ScriptJobs,而微任务又称PromiseJobs

4:构造函数,原型和原型链

构造函数:constructor返回创建实例对象时构造函数的引用。此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。例:function Parent(age){this.age = age;} var p = new Parent(50); p.constructor === Parent   // true,此处的相等告诉我们属性值就是对函数本身的引用。

构造函数本身就是一个函数,与普通函数没有任何区别,构造函数与普通函数的区别在于,使用new生成实例的函数就是构造函数,直接调用就是普通函数

普通函数创建的实例一般没有constructor属性,但是当普通函数具有有效返回值的时候,也会有constructor,但是此时的constructor其实是返回值的constructor

原型:prototype,JavaScript是一种基于原型的语言,这个和Java等基于类的语言不一样,但是有很多相通之处,所以一定要多想想Java是怎么运行的。每个对象拥有一个原型对象,对象以其原型为模板,从原型继承方法和属性,这些属性和方法定义在对象的构造函数的prototype属性上,而非对象实例本身。

循环引用:构造函数Parent的prototype为原型(Parent.prototype),原型的constructor为构造函数

_proto_:_proto_是实例的属性,prototype是构造函数的属性,但是两个属性指向相同

image-20190211200314401

原型链:每个对象拥有一个原型对象,通过_proto_指针指向上一个原型,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层最终指向null,这就是原型链

5,JS继承

继承需要继承父函数的属性和方法,还需要继承父函数原型链的属性和方法

// 定义一个动物类
function Animal (name) {
  // 属性
  this.name = name || 'Animal';
  // 实例方法
  this.sleep = function(){
    console.log(this.name + '正在睡觉!');
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
(function(){
  // 创建一个没有实例方法的类
  var Super = function(){};
  Super.prototype = Animal.prototype;
  //将实例作为子类的原型
  Cat.prototype = new Super();
})();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

// 实现继承的函数
function (fn1, fn2) {
    
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值