javascript专题二2023年失业,新冠

instanceof函数

原理

instanceof 判断基本数据类型的方法

instanceof运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

其实就是自定义 instanceof 行为的一种方式,这里将原有的 instanceof 方法重定义,换成了 typeof,因此能够判断基本数据类型。

instanceof 语法

function Foo () {
}
let f = new Foo();
console.log(f instanceof Foo); // true

 实列

[] instanceof Array; // true
[] instanceof Object; // true
Array instanceof Object; // true
Object instanceof Array; // false

Object instanceof Object; // true
Number instanceof Number; // false
Array instanceof Array; // false

Function instanceof Object; // true
Object instanceof Function; // true
Object instanceof Object; // true
Function instanceof Function; // true
String instanceof Function; // true
Array instanceof Function; // true
Number instanceof Function; // true

"" instanceof String; // false
1 instanceof Number; // false
false instanceof Boolean; // false

错误使用的报错

Array instanceof [];
// Uncaught TypeError: Right-hand side of 'instanceof' is not callable
{} instanceof Object;
// VM91:1 Uncaught SyntaxError: Unexpected token 'instanceof'

判断Object的prototype是否在a的原型链上。

#实现

    function myInstanceof(target, origin) {
      const proto = target.__proto__;
      if (proto) {
        if (origin.prototype === proto) {
          return true;
        } else {
          return myInstanceof(proto, origin)
        }
      } else {
        return false;
      }
    }

 ES5继承

每个函数都会创建一个prototype属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法都可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型。

有下面两个类,下面实现Man继承People

    function People() {
      this.type = 'prople'
    }

    People.prototype.eat = function () {
      console.log('吃东西啦');
    }

    function Man(name) {
      this.name = name;
      this.color = 'black';
    }

#原型继承

将父类指向子类的原型。

Man.prototype = new People();

缺点:原型是所有子类实例共享的,改变一个其他也会改变。


#构造继承

在子类构造函数中调用父类构造函数

    function Man(name) {
      People.call(this);
    }

缺点:不能继承父类原型,函数在构造函数中,每个子类实例不能共享函数,浪费内存。

#组合继承

使用构造继承继承父类参数,使用原型继承继承父类函数

    function Man(name) {
      People.call(this);
    }

    Man.prototype = People.prototype;

缺点:父类原型和子类原型是同一个对象,无法区分子类真正是由谁构造。

#寄生组合继承

在组合继承的基础上,子类继承一个由父类原型生成的空对象。

    function Man(name) {
      People.call(this);
    }

    Man.prototype = Object.create(People.prototype, {
      constructor: {
        value: Man
      }
    })

#inherits函数:

方法的内部会进行严格的参数合法性检查,参数必须是两个,即一个子类,一个父类;另外还要求两个参数都必须是function类型,否则抛出异常,宣告继承失败

原理

instanceof 判断基本数据类型的方法

其实就是自定义 instanceof 行为的一种方式,这里将原有的 instanceof 方法重定义,换成了 typeof,因此能够判断基本数据类型。

a instanceof Object

判断Object的prototype是否在a的原型链上。

#实现

    function myInstanceof(target, origin) {
      const proto = target.__proto__;
      if (proto) {
        if (origin.prototype === proto) {
          return true;
        } else {
          return myInstanceof(proto, origin)
        }
      } else {
        return false;
      }
    }

 ES5继承

每个函数都会创建一个prototype属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实际上,这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法都可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型。

有下面两个类,下面实现Man继承People

    function People() {
      this.type = 'prople'
    }

    People.prototype.eat = function () {
      console.log('吃东西啦');
    }

    function Man(name) {
      this.name = name;
      this.color = 'black';
    }

#原型继承

将父类指向子类的原型。

Man.prototype = new People();

缺点:原型是所有子类实例共享的,改变一个其他也会改变。


#构造继承

在子类构造函数中调用父类构造函数

    function Man(name) {
      People.call(this);
    }

缺点:不能继承父类原型,函数在构造函数中,每个子类实例不能共享函数,浪费内存。

#组合继承

使用构造继承继承父类参数,使用原型继承继承父类函数

    function Man(name) {
      People.call(this);
    }

    Man.prototype = People.prototype;

缺点:父类原型和子类原型是同一个对象,无法区分子类真正是由谁构造。

#寄生组合继承

在组合继承的基础上,子类继承一个由父类原型生成的空对象。

    function Man(name) {
      People.call(this);
    }

    Man.prototype = Object.create(People.prototype, {
      constructor: {
        value: Man
      }
    })

#inherits函数:

方法的内部会进行严格的参数合法性检查,参数必须是两个,即一个子类,一个父类;另外还要求两个参数都必须是function类型,否则抛出异常,宣告继承失败

每个函数就是一个对象(Function),函数对象都有一个子对象 prototype对象,类是以函数的形式来定义的。prototype表示该函数的原型,也表示一个类的成员的集合。


function inherits(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
}; 

使用:

function Man() {
  People.call(this);
  //...
}
inherits(Man, People);

Man.prototype.fun = ...

function inherits(ctor, superCtor) {
  ctor.super_ = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
}; 

使用:

function Man() {
  People.call(this);
  //...
}
inherits(Man, People);

Man.prototype.fun = ...

 promise封装一个ajax

步骤

  1. 首先,通过new XMLHttpRequest创建一个xhr对象。
  2. 根据get方法和post方法进行数据请求,在使用这个xhr对象时,要调用的第一个方法是open()
xhr.open("get",url,false)

调用open并不会真正的发送请求,只是启动一个请求以备发送。

  1. 发送请求时调用send()方法
xhr.send(data);//对应post方法
xhr.send(null);//对应get方法

send方法接受一个参数,作为请求主体发送的数据。如果不需要通过请求主体发送数据最好传入null。

  1. 如果仅仅是同步请求,接下来就可以根据xhr.status属性来判断数据请求情况。status就是响应的HTTP状态码。注意304这一特殊状态码。
    function ajax(url, method = 'get', param = {}) {
      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        const paramString = getStringParam(param);
        if (method === 'get' && paramString) {
          url.indexOf('?') > -1 ? url += paramString : url += `?${paramString}`
        }
        xhr.open(method, url);
        xhr.onload = function () {
          const result = {
            status: xhr.status,
            statusText: xhr.statusText,
            headers: xhr.getAllResponseHeaders(),
            data: xhr.response || xhr.responseText
          }
          if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
            resolve(result);
          } else {
            reject(result);
          }
        }
        // 设置请求头
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        // 跨域携带cookie
        xhr.withCredentials = true;
        // 错误处理
        xhr.onerror = function () {
          reject(new TypeError('请求出错'));
        }
        xhr.timeout = function () {
          reject(new TypeError('请求超时'));
        }
        xhr.onabort = function () {
          reject(new TypeError('请求被终止'));
        }
        if (method === 'post') {
          xhr.send(paramString);
        } else {
          xhr.send();
        }
      })
    }

    function getStringParam(param) {
      let dataString = '';
      for (const key in param) {
        dataString += `${key}=${param[key]}&`
      }
      return dataString;
    }

单列模式

在合适的时候才创建对像,并且只创建唯一的一个。

创建对象和管理单例的职责被分布在两个不同的方法中,这两个方法组合起来才具有单例模式的威力。

使用闭包实现:

var Singleton = function(name) {
    this.name = name;
};

Singleton.prototype.getName = function() {
    alert(this.name);
};

Singleton.getInstance = (function(name) {
    var instance;
    return function(name){
        if (!instance) {
            instance = new Singleton(name);
        }
        return instance;
    }
})();

var a = Singleton.getInstance('ConardLi');
var b = Singleton.getInstance('ConardLi2');

console.log(a===b);   //true

异步循环打印

如果程序就这样一步步的执行下去,条例清晰,但是当我们遇到阻塞时,比如一个耗时的Ajax请求,或者读写文件之类的操作,由于js是单线程的,其他后续的操作也都将被阻塞,我们就需要异步的进行一些操作

var response = fetch('myImage.png');
var blob = response.blob();
// display your image blob in the UI somehow


对于上面的代码来说,fetch提供了异步读取网络文件的能力,相当于将fetch行为加入了异步队列中,只能等待同步的代码执行完成之后才会开始清理异步队列的任务。这就是一个异步编程,但是这是有问题的,因为fetch行为是处于异步队列的,后续的代码不能确定什么时候获取到response,此时引入callback(回调函数),或者promise

异步callbacks
异步callbacks其实就是函数,只不过作为参数传递给那些异步执行的其他函数,当异步执行的函数

 

使用promise + async await实现异步循环打印

    var sleep = function (time, i) {
      return new Promise(function (resolve, reject) {
        setTimeout(function () {
          resolve(i);
        }, time);
      })
    };


    var start = async function () {
      for (let i = 0; i < 6; i++) {
        let result = await sleep(1000, i);
        console.log(result);
      }
    };

    start();

图片懒加载

监听图片高度

图片,用一个其他属性存储真正的图片地址:

  <img src="loading.gif" data-src="https://cdn.pixabay.com/photo/2015/09/09/16/05/forest-931706_1280.jpg" alt="">
  <img src="loading.gif" data-src="https://cdn.pixabay.com/photo/2014/08/01/00/08/pier-407252_1280.jpg" alt="">
  <img src="loading.gif" data-src="https://cdn.pixabay.com/photo/2014/12/15/17/16/pier-569314_1280.jpg" alt="">
  <img src="loading.gif" data-src="https://cdn.pixabay.com/photo/2010/12/13/10/09/abstract-2384_1280.jpg" alt="">
  <img src="loading.gif" data-src="https://cdn.pixabay.com/photo/2015/10/24/11/09/drop-of-water-1004250_1280.jpg"

通过图片offsetTopwindowinnerHeightscrollTop判断图片是否位于可视区域。

    var img = document.getElementsByTagName("img");
    var n = 0; //存储图片加载到的位置,避免每次都从第一张图片开始遍历
    lazyload(); //页面载入完毕加载可是区域内的图片
    // 节流函数,保证每200ms触发一次
    function throttle(event, time) {
      let timer = null;
      return function (...args) {
        if (!timer) {
          timer = setTimeout(() => {
            timer = null;
            event.apply(this, args);
          }, time);
        }
      }
    }
    window.addEventListener('scroll', throttle(lazyload, 200))
    function lazyload() { //监听页面滚动事件
      var seeHeight = window.innerHeight; //可见区域高度
      var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; //滚动条距离顶部高度
      for (var i = n; i < img.length; i++) {
        console.log(img[i].offsetTop, seeHeight, scrollTop);
        if (img[i].offsetTop < seeHeight + scrollTop) {
          if (img[i].getAttribute("src") == "loading.gif") {
            img[i].src = img[i].getAttribute("data-src");
          }
          n = i + 1;
        }
      }
    }

#IntersectionObserver

IntersectionObserver接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport)被称为根(root)。

Intersection Observer可以不用监听scroll事件,做到元素一可见便调用回调,在回调里面我们来判断元素是否可见。

    if (IntersectionObserver) {
      let lazyImageObserver = new IntersectionObserver((entries, observer) => {
        entries.forEach((entry, index) => {
          let lazyImage = entry.target;
          // 如果元素可见            
          if (entry.intersectionRatio > 0) {
            if (lazyImage.getAttribute("src") == "loading.gif") {
              lazyImage.src = lazyImage.getAttribute("data-src");
            }
            lazyImageObserver.unobserve(lazyImage)
          }
        })
      })
      for (let i = 0; i < img.length; i++) {
        lazyImageObserver.observe(img[i]);
      }
    }

 心心念念的后续来了,赶快学习起来吧,防止丢失一键三联,加关注,评论区留言,666

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客云曦

你的鼓励就是我最大的创作动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值