js 遍历对象_js高频问题(二)

30.typescript与js的比较


js主要特点:

  • JavaScript 是一种脚本编写语言,无需编译,只要嵌入 HTML 代码中,就能由浏览器逐行加载解释执行。

  • JavaScript 是一种基于对象的语言,可以创建对象同时使用现有对象。但是 Javascript 并不支持其它面向对象语言所具有的继承和重载功能。

  • JavaScript 的语法简单,使用的变量为弱类型。

  • JavaScript 语言较为安全,仅在浏览器端执行,不会访问本地硬盘数据。

  • JavaScript 语言具有动态性。JavaScript 是事件驱动的,只根据用户的操作做出相应的反应处理。

  • JavaScript 只依赖于浏览器,与操作系统的因素无关。因此 JavaScript 是一种跨平台的语言。

  • JavaScript 兼容性较好,能够与其他技术(如 XML,REST API 等)一起使用。

ts主要特点:

  • TypeScript 是 Microsoft 推出的开源语言,使用 Apache 授权协议

  • TypeScript 增加了静态类型、类、模块、接口和类型注解

  • TypeScript 可用于开发大型的应用

  • TypeScript 易学易于理解

    js和ts的主要差异:

  • TypeScript 从核心语言方面和类概念的模塑方面对 JavaScript 对象模型进行扩展。

  • JavaScript 代码可以在无需任何修改的情况下与 TypeScript 一同工作,同时可以使用编译器将 TypeScript 代码转换为 JavaScript。

  • TypeScript 通过类型注解提供编译时的静态类型检查。

  • TypeScript 中的数据要求带有明确的类型,JavaScript不要求。

  • TypeScript 为函数提供了缺省参数值。

  • TypeScript 引入了 JavaScript 中没有的“类”概念。

  • TypeScript 中引入了模块的概念,可以把声明、数据、函数和类封装在模块中。

31.new操作符的流程(构造函数实现原理)


1、创建一个空对象

var obj = new Object();

2、设置原型链(当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象)

obj.__proto__= Func.prototype;

3、让Func中的this指向obj,并执行Func的函数体。(创建新的对象之后,将构造函数的作用域赋给新对象(因此this就指向了这个新对象))

var result =Func.call(obj);

32.for in 和for of


1.for in 遍历数组会遍历到数组原型上的属性方法,更适合遍历对象;

2.forEach 不支持break,continue,return;

3.for of可以成功遍历数组的值,而不是索引,不会遍历原型;

4.for in 可以遍历到myObject的原型方法method,如果不想遍历原型方法和属性的话,可以在循环内部判断一下,hasOwnPropery方法可以判断某属性是否是该对象的实例属性

33.JS实现并发控制


递归方式实现:

//递归方式

function handleFetchQueue(urls, max, callback) {

let urlsCopy = [...urls]; //防止影响外部urls变量

let count = 0; //几率并发数

request();

function request() {

count++;

console.log('start 当前并发数为: ' + count);

//请求

fetch(urlsCopy.shift()).then(Handle).catch(Handle);

//并发数不足时递归

count < max && request();

function Handle() {

count--;

console.log('end 当前并发数为: ' + count);

if (urlsCopy.length) { //还有未请求的则递归

request();

} else if (count === 0) { //并发数为0则表示全部请求完成

callback()

}

}

}

}

promise方式实现:

function sendResquest(urls, max, callback) {

let pending_count = 0, //并发数

idx = 0; //当前请求的位置

while (pending_count < max) {

_fetch(urls[idx++])

}

async function _fetch(url) {

if (!url) return;

pending_count++;

console.log(url + ':start', '并发数: ' + pending_count);

await fetch(url)

pending_count--;

console.log(url + ':done', '并发数: ' + pending_count);

_fetch(urls[idx++]);

pending_count || callback && callback()

}

}

验证:

let urls = Array.from({

length: 10

}, (v, k) => k);//[0,1,2,3,4,5,6,7,8,9];模拟url序列

let fetch = function (idx) {//模拟fetch

return new Promise(resolve => {

let timeout = parseInt(Math.random() * 1e4);

setTimeout(() => {

resolve(idx)

}, timeout)

})

};

let max = 4;//最大并发数

let callback = () => {//回调函数

console.log('run callback');

};

//执行

handleFetchQueue(urls, max, callback);//分别调用 ;

sendResquest(urls, max, callback);

34.ajax、axios、fetch比较


原生ajax:

1.使用起来也比较繁琐,需要设置很多值。

2.早期的IE浏览器有自己的实现,这样需要写兼容代码

3.如果有多个请求,并且有依赖关系的话,容易形成回调地狱。

4.本身是针对MVC的编程,不符合现在前端MVVM的浪潮。

fetch:

  1. fetch只对网络请求报错,对 400, 500都当做成功的请求,需要封装去处理

  2. fetch默认不会带 cookie,需要添加配置项。

  3. fetch不支持 abort,不支持超时控制,使用 setTimeout及 Promise.reject的实现超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费。

  4. fetch没有办法原生监测请求的进度,而 XHR可以。

axios:

  1. 从浏览器中创建 XMLHttpRequests

  2. 从 node.js 创建 http 请求

  3. 支持 Promise API

  4. 拦截请求和响应

  5. 转换请求数据和响应数据

  6. 取消请求

  7. 自动转换 JSON 数据

  8. 客户端支持防御 XSRF

总结:

ajax是最早出现发送后端请求的技术,属于原生js范畴,核心是使用XMLHttpRequest对象,使用较多并有先后顺序的话,容易产生回调地狱。

fetch号称可以代替ajax的技术,是基于es6中的Promise对象设计的,参数和jQuery中的ajax类似,它并不是对ajax进一步封装,它属于原生js范畴。没有使用XMLHttpRequest对象。

axios不是原生js,使用时需要对其进行安装,客户端和服务器端都可以使用,可以在请求和相应阶段进行拦截,基于promise对象。

35.promise.race、promise.all实现

先写个方法,用来判断是不是promise:

function isPromise(obj) {

return obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';

}

promise.all:

Promise.all = function (promiseArr) { //传入promise数组

if (!Array.isArray(promiseArr)) {

throw new TypeError('You must pass array')

}

for (let i of promiseArr) {

if (!isPromise(i)) {

throw new TypeError('not Promise')

}

}

let results = []; //用来收集各个promise的结果

let promiseCount = 0; //标记是否都执行 ?== promisesLength

let promisesLength = promiseArr.length;

return new Promise(function (resolve, reject) {

for (let val of promiseArr) { //遍历

Promise.resolve(val).then(function (res) {

results[promiseCount] = res; //存入结果

promiseCount++; //标志加一

// 当所有函数都正确执行了,resolve输出所有返回结果。

if (promiseCount === promisesLength) {

return resolve(results);

}

}, function (err) { //有错误直接抛出

return reject(err);

});

}

});

};

promise.race:

Promise.race = function(promiseArr){

if (!Array.isArray(promiseArr)) {

throw new TypeError('You must pass array')

}

for (let i of promiseArr) {

if (!isPromise(i)) {

throw new TypeError('not Promise')

}

}

return new Promise(function(resolve,reject){

for(let i = 0;i<promiseArr.length;i++){

promiseArr[i].then(resolver,rejecter);

}

function resolver(res){

resolve(res);

}

function rejecter(error){

reject(error);

}

})

}

测试:

let p1 = Promise.resolve('hello I am No1');

let p2 = Promise.resolve('hello I am No1');

let p3 = Promise.resolve('hello I am No3');

Promise.all([p2,p1,p3]).then((value) => {

console.log(value);

});

//输出:hello I am No2

// hello I am No1

// hello I am No3

Promise.race([p2,p1,p3]).then((value) => {

console.log(value)

});

//输出:hello I am No2

36.symbol实现原理

ES6引入了一-种新的原始数据类型Symbol,表示独一无二的值。

主要特性:

  1. Symbol值通过Symbol函数生成,使用typeof,结果为"symbol"

var s = Symbol();

console. log(typeof s); // "symbol"

  1. Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不 是对象。

  2. instanceof的结果为false

var S = Symbol('foo');

console.1og(s instanceof Symbol); // false

  1. Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。

var s1 = Symbol('foo');

console.1og(s1); // Symbol(foo)

5.如果Symbol的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,然后才生成一个Symbol值。

const obj = {

toString() {

return ' abc' ;

}

};

const sym = Symbol(obj);

console.1og(sym); // Symbol(abc)

6.Symbol函数的参数只是表示对当前Symbol值的描述,相同参数的Symbol函数的返回值是不相等的。

//没有参数的情况

var s1 = Symbol();

var s2 = Symbol();

console.1og(s1 === s2); // false

//有参数的情况

var s1 = Symbol('foo' );

var s2 = Symbol('foo');

console.1og(s1 === s2); // false

7.Symbol值不能与其他类型的值进行运算,会报错。

var sym = Symbol('My symbol');

console. log("your symbol is " + sym); // TypeError: can't convert symboL to string

8.Symbol值可以显式转为字符串。

var sym = Symbol('My symbol');

console. log(String(sym)); // 'Symbol (My symbol) '

console. log( sym. tostring()); // 'Symbol (My symbol) '

9.Symbol值可以作为标识符,用于对象的属性名,可以保证不会出现同名的属性。

var mySymbol = Symbol();

//第一种写法

vara={};

a[mySymbol] = 'Hello!';

//第二种写法

vara = {

[mySymbol]: 'Hello!

};

//第三种写法

vara={};

object . defineProperty(a, mySymbol, { value: 'Hello!' });

//以上写法都得到同样结果

console. log(a[mySymbol]); // "Hello!"

10.Symbol作为属性名,该属性不会出现在fr..in、fr..of 循环中,也不会被Object.keys()、 Object.getOwnPropertyNames()、JSON.stringify() 返回。但是,它也不是私有属性,有一个 Object.getOwnPropertySymbols方法,可以获取指定对象的所有Symbol属性名。

var obj = {};

var a = Symbol('a');

var b = Symbol('b');

obj[a] = 'Hello';

obj[b] = 'World';

var objectsymbols = object . getOwnPropertysymbols(obj);

console. log(objectsymbols);

// [Symbol(a),Symbol(b)]

11.如果我们希望使用同一个Symbol值,可以使用Symbol.for。它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。

var s1 = Symbol.for('foo' );

var s2 = Symbol.for('foo');

console.log(s1 === s2); // true

12.Symbol.keyFor方法返回-个已登记的Symbol类型值的key。

var s1 = Symbol.for("foo");

console.log(Symbol.keyFor(s1)); // "foo"

var s2 = Symbol("foo");

console.log(Symbol. keyFor(s2) ); // undefined

37.ES6的装饰器


装饰器是一种函数,写成@ + 函数名。它可以放在类和类方法的定义前面。

许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为。

例1:

@testable

class MyClass {};

function testable(target) {

target.isTestable = true;

}

MyClass.isTestable; // true

上面代码中,@testable就是一个修饰器。它修改了MyClass这个类的行为,为它加上了静态属性isTestable。

例2:

@decorator

class A {};

// 等同于

class A {};

A = decorator(A) || A;

也就是说,修饰器是一个对类进行处理的函数。修饰器函数的第一个参数,就是所要修饰的目标类。

注意,修饰器对类的行为的改变,是代码编译时发生的,而不是在运行时。这意味着,修饰器能在编译阶段运行代码。也就是说,修饰器本质就是编译时执行的函数。

如果觉得一个参数不够用,可以在修饰器外面再封装一层函数。见下面

例3:

function testDecorator(desc) {

return function(target) {

target.addedParam = desc;

}

}

//调用testDecorator函数之后,其又返回一个匿名函数,利用闭包的特性使用了decs变量

@testDecorator("operate one")

class ClassA {

}

console.log(ClassA.addedParam) // operate one

38.实现fetch abort(中止请求)


// 创建 AbortController 的实例

const controller = new AbortController()

const signal = controller.signal

// API 10s 后返回相应

// https://slowmo.glitch.me/10000 10000 代表 10s 后返回相应值

//fetch 接受Signal 作为第二个参数的一部分。

fetch('https://slowmo.glitch.me/10000', {

signal

})

.then(r => r.json())

.then(response => console.log(response))

.catch(err => {

if (err.name === 'AbortError') {

console.log('Fetch was aborted')

} else {

console.log('Error', err)

}

})

// 在 5s 后中断请求,将触发 'AbortError'

setTimeout(() => controller.abort(), 5000);

40.使用xhr实现fetch


// 先实现ajax

function ajax(method,url,data,suc,fail) {

if (window.XMLHttpRequest)

{

// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码

xhr=new XMLHttpRequest();

}

else

{

// IE6, IE5 浏览器执行代码

xhr=new ActiveXObject("Microsoft.XMLHTTP");

}

xhr.open(method, url, true);

xhr.onreadystatechange = function () {

if(xhr.readyState == 4){

if(xhr.status == 200){

suc(xhr.responseText)

} else {

console.log(err);

fail(xhr.responseText);

}

}

};

xhr.send(data);

}

// 再实现promise

function promise () {

this.msg = '' // 存放value和error

this.status = 'pending'

var that = this

var process = arguments[0]

process (function () {

that.status = 'fulfilled'

that.msg = arguments[0]

}, function () {

that.status = 'rejected'

that.msg = arguments[0]

})

return this

}

promise.prototype.then = function () {

if (this.status === 'fulfilled') {

arguments[0](this.msg)

} else if (this.status === 'rejected' && arguments[1]) {

arguments[1](this.msg)

}

}

//fetch

function fetch(method, url, data) {

return new promise(function (resolve,reject) {

ajax(method, url, data, function (res) {

resolve(res);

},function (err) {

reject(err);

})

})

}

41.js基本数据类型与引用数据类型的存储


JS 的数据类型有几种:

Number、String、Boolean、Null、undefined、object、symbol

Object 中包含了哪几种类型:

Date、function、Array等

JS的基本类型和引用类型有哪些呢:

基本类型:String、Number、boolean、null、undefined、symbol

引用数据类型:object

jS 中 typeof 输出分别是什么:

c1a03e0e8623d1bde50de5c2dec01a52.png

null 和 undefined 有什么区别:

1.Null 只有一个值,是 null。不存在的对象。

2.Undefined 只有一个值,是undefined。没有初始化。

3.undefined 是从 null 中派生出来的。

简单理解就是:undefined 是没有定义的,null 是定义了但是为空

== 和 === 有什么区别,什么场景下使用:

1、对于string,number等基础类型,==和===是有区别的

不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等

同类型比较,直接进行“值”比较,两者结果一样

2、对于Array,Object等高级类型,==和===是没有区别的

3、基础类型与高级类型,==和===是有区别的

对于==,将高级转化为基础类型,进行“值”比较

因为类型不同,===结果为false

42.this指向


this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象;

另外,call,apply,bind可以改变this的指向(实现见 题8);

43.图片懒加载和预加载的实现


懒加载:

html:

src="./images/birthday_flower(20).jpg" src="./images/love_flower(1).png" alt="">

src="./images/birthday_flower(20).jpg" src="./images/love_flower(3).jpg" alt="">

<script>

var num = document.getElementsByTagName('img').length;

var img = document.getElementsByTagName("img");

// 存储图片加载到的位置,避免每次都从第一张图片开始遍历

var n = 0;

// 页面载入完毕加载可视区域内的图片

window.addEventListener("scroll",function lazyload() {

// 可见区域高度

var seeHeight = document.documentElement.clientHeight;

console.log('seeHeight: ', seeHeight);

// 滚动条距离顶部高度

var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;

console.log('scrollTop: ', scrollTop);

for (var i = n; i < num; i++) {

if (img[i].offsetTop < seeHeight + scrollTop) {

if (img[i].getAttribute("src") == "./images/birthday_flower(20).jpg") {

img[i].src = img[i].getAttribute("src");

}

n = i + 1;

}

}

},false);

// 监听页面滚动事件

script>

预加载:

纯css:

原理是加载了该图片,但是我们不显示在可视范围内:

body:after {

content: "";

display: block;

position: absolute;

background: url("../image/manage/help/help_item2_01.png?v=201707241359") no-repeat -10000px -1000px;

width: 0;

height: 0

}

纯js:

//存放图片路径的数组

var imgSrcArr = [

'imgsrc1',

'imgsrc2',

'imgsrc3',

'imgsrc4'

];

var imgWrap = [];

function preloadImg(arr) {

for(var i =0; i< arr.length ;i++) {

imgWrap[i] = new Image();

imgWrap[i].src = arr[i];

}

}

preloadImg(imgSrcArr);

//或者延迟的文档加载完毕在加载图片

js+css:

比如我们写了上面的这样一个类,但是页面中没有用到,我们在文档加载完毕之后,给某个元素添加该类

.preload-img:after{

content:"",

background: url("../image/manage/help/help_item2_01.png?v=201707241359") no-repeat -10000px -1000px,

}

var target = document.getElementById(".target");

target.setAttribute("class") = "preload-img";

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值