JavaScript常用知识(持续更新中...)

15、展开语法(Spread syntax)

  • 函数调用入参展开
function sum(x, y, z) {
  return x + y + z;
}
 
const numbers = [1, 2, 3];
 
// expected output: 6
console.log(sum(...numbers));
  • 字面量数组构造或字符串,如[...iterableObj, '4', ...'hello', 6];
    构造字面量对象时,进行克隆或者属性拷贝(ECMAScript 2018规范新增特性)。
/*
* 字典对象
*/
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
 
var clonedObj = { ...obj1 };
// 克隆后的对象: { foo: "bar", x: 42 }
 
var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 }



/*
* 数组对象
*/
var parts = ['shoulders', 'knees']; 
var lyrics = ['head', ...parts, 'and', 'toes']; 
// ["head", "shoulders", "knees", "and", "toes"]


// 数组拼接
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2];


/*
* 拷贝行为,以数组为例
*/ 
var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4); 
// arr2 此时变成 [1, 2, 3, 4]
// arr 不受影响

14、JavaScript函数

  • js函数中有个储存参数的数组arguments ,所有函数获得的参数会被编译器挨个保存到这个数组中
function sum (){
  var a = arguments[0];
  var b = arguments[1];
  return a+b;
}

// 等价于 
function sum (a, b){
  return a+b;
}
  • 调用该函数的时候,不需要传入所有的参数,它就能正常执行,未入参的参数默认就是undefined

多参数和可选参数

  • 永远只能把可选参数连续地声明在函数的末端,必要的参数必须得放前面
function Person(name, age, height, weight) {
    ...
}

// 这时候age="170cm",调用出错
var person = new Person("Turtle", "170cm");
  • 单一的字典参数,变相解决多参数问题:


    image.png

13、JavaScript的内存机制

JavaScript内存优化

  • 作用域(scope)
    使用var 声明的变量是局部变量,不使用var 直接写变量名是全局变量(更准确的是说,默认被添加到全局window属性中去了)。
/* 例子1 */ 
var foo = function() {
  var local = {}; // 局部变量
};
foo();
console.log(local); //=> undefined

/* 例子2 */ 
var bar = function() {
  local = {}; // 全局变量
};
bar();
console.log(local); //=> {}

12、const、let、var

js中let和var定义变量的区别

  • const
    不可以修改,而且必须初始化,否则会报错。
  • var
    可以修改,如果不初始化会输出undefined,不会报错。
  • let
    第一次接触let关键字,有一个要非常非常要注意的概念就是”javascript 严格模式”
// let遵守 ”javascript 严格模式” ,不加会报错
'use strict'; 

let hello = 'hello world.';
console.log(hello);

块级作用域:函数内部使用let定义后,对函数外部无影响。

'use strict';

// 例子 1
let c = 3;
console.log('函数外let定义c:' + c);//输出c=3


function change(){
    let c = 6;
    console.log('函数内let定义c:' + c);//输出c=6
}
change();
console.log('函数调用后let定义c不受函数内部定义影响:' + c);//输出c=3

// 例子 2
(function() {
  var varTest = 'test var OK.';
  let letTest = 'test let OK.';

  {
    var varTest = 'varTest changed.';
    let letTest = 'letTest changed.';
  }

  console.log(varTest); //输出"varTest changed.",内部"{}"中声明的varTest变量覆盖外部的letTest声明
  console.log(letTest); //输出"test let OK.",内部"{}"中声明的letTest和外部的letTest不是同一个变量
}());

11、判断变量值是否为空?

JavaScript的空值有:undefined、 null、 ''、 NaN、false、0、[]、{} 、空白字符串

本身没有判断一个变量值是不是空值的函数,因为变量有可能是string,object,number,boolean等类型,类型不同,判断方法也不同。

function isEmpty(v) {
    switch (typeof v) {
    case 'undefined':
        return true;
    case 'string':
        if (v.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true;
        break;
    case 'boolean':
        if (!v) return true;
        break;
    case 'number':
        if (0 === v || isNaN(v)) return true;
        break;
    case 'object':
        // 如:数组
        if (null === v || v.length === 0) return true; 
        // 如:字典
        for (var i in v) {
            return false;
        }
        return true;
    }
    return false;
}

10、JavaScript的单例模式

JS设计模式之单例模式

  • 通过函数属性构造单例
function Single(){}
Single.getInstance=function(){
    if(!this.instance){
        this.instance=new Single();
    }
    return this.instance
};

// 实例化
let a=Single.getInstance();
let b=Single.getInstance();
console.log(a===b);//true

9、Object.assign()

  • Object.assign(target, ...sources)
    用于将所有可枚举属性的值从一个或多个源对象分配到目标对象;它将返回目标对象。
    对于target和sources之间相同的属性是直接覆盖的,如果属性值为对象,是不会对对象直接的属性进行合并的。
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }
  • Object.assign()到底是深拷贝还是浅拷贝?
    如果对象的属性值为简单类型,如string、number等,通过Object.assign(...);得到的新对象为深拷贝;如果属性值为对象或其他引用类型,那对于这个对象而言其实是浅拷贝的。

8、JavaScript中的this和self之间的区别

https://www.itranslater.com/qa/details/2325926566821364736

  • this
    每个函数在定义被ECMAScript解析器解析时,都会创建两个特殊的变量:this和arguments。这个this对象是在运行时基于函数的执行环境绑定的。
    因此,如果在在全局对象中,this指向的是window对象;在自定义函数中,this对象指向的是调用这个函数的对象。

  • self
    浏览器会首先创建一个窗口,这个窗口就是一个window对象,也是js运行所依附的全局环境对象和全局作用域对象。self 指窗口本身,它返回的对象跟window对象是一模一样的。

7、数组遍历方法和效率

JS几种数组遍历方式总结

image.png

6、TypeScript(为狂奔的JS套上规矩)

菜鸟-TypeScript 教程

image.png

6.1 ES6

ES6教程-阮一峰

5、Promise原理

  • callbacks队列:保存状态变化的回调方法。
  • 状态机制:引入pending --> fulfilled/rejected三个状态及其变化。
  • 异步机制,利用setTimeout延迟异步执行。
  • 链式机制:在所有方法返回Promise,即可实现链式操作。

30分钟,让你彻底明白Promise原理

4、异步处理,Promise(ES6)

有且只有只有三种状态:pending --> fulfilled/rejected(成功/失败)

这三种状态不受外界影响,而且状态只能从pending改变为resolved或者rejected,并且不可逆。

var promise = new Promise(function(resolve, reject) {
    // 异步处理
    if (success) { 
        resolve(); 
    } else {
        reject();
    }
});
.then方法

1、可以接收构造函数中处理的状态变化,并分别对应执行。
2、方法有2个参数,第一个函数接收resolved状态的执行,第二个参数接收reject状态的执行,参数可以为空。
3、方法的执行结果会返回一个Promise对象,因此可以进行then的链式执行,这也是解决回调地狱的主要方式。

var fn = function(num) {
    return new Promise(function(resolve, reject) {
        if (typeof num == 'number') {
            resolve(num);
        } else {
            reject('TypeError');
        }
    })
}

/*
* 1、then方法的两个参数
*/ 
fn(1).then((num)=>{
    console.log('参数1:数字 ' + num);
}, (num)=>{
    console.log('参数2:非数字 ' + num);
});

fn('abc').then(null, (num)=>{
    console.log('参数2:非数字 ' + num);
});

/* 
* 2、级联
*/ 
fn(2).then(function(num) {
    console.log('first: ' + num);
    return num + 1;
})
.then(function(num) {
    console.log('second: ' + num);
    return num + 1;
})
.then(function(num) {
    console.log('third: ' + num);
    return num + 1;
});

// 输出结果
first: 2
second: 3
third: 4
.catch 错误捕获
.catch(function(err) {
    console.log(err);
})
Promise.all

Promise.all接收一个Promise对象组成的数组作为参数,当这个数组所有的Promise对象状态都变成resolved或者rejected的时候,它才会去调用then方法。

使用场景:task1、task2并行执行,等待前两个任务都执行完后,流程才能继续,才能执行task3.

Promise.race

只要当数组中的其中一个Promsie状态变成resolved或者rejected时,就可以调用.then方法了,只会调用一次.then方法。
使用场景:可以用race给某个异步请求设置超时时间,并且在超时后执行相应的操作。

3、js文件/模块导入和导出

module.exports与exports,export与export default之间的关系和区别

CommonJS模块规范(一切以module为主,关键字module.exportsrequire

根据这个规范,每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

// 1、example.js 文件
var x = 5;
var addX = function (value) {
  return value + x;
};
module.exports.x = x;
module.exports.addX = addX;

// 或者
module.exports = {
    x,
    addX
}

// 2、导入文件
var example = require('./example.js');
console.log(example.x); // 5
console.log(example.addX(1)); // 6
exportsmodule.exports 的区别
  • exports 返回的是模块函数,可以直接调用。
  • module.exports 返回的是模块对象本身,返回的是一个类;要new对象之后才可以调用。

ES6模块规范

ES6使用 exportimport 来导出、导入模块。

// Name Export | Name Import 命名输出
export const name = 'value'
import { name } from '...'

// Default Export | Default Import;默认输出
export default 'value'
import anyName from '...'

// Rename Export | NameImport;重命名输出
export { name as newName }
import { newName } from '...'

// Name + Default | Import All  全部导入
export const name = 'value'
export default 'value'
import * as anyName from '...'

// Export List + Rename | Import List + Rename  列表输出
export {
  name1,
  name2 as newName2
}
import {
  name1 as newName1,
  newName2
} from '...'

Module Cheatsheet

2、定时器

  • 设置定时器
setTimeout(function,delay);  //设置延时多少毫秒执行该函数,只执行一次,返回值是一个id
setInterval(function,delay);  //设置间隔多少毫米一直执行该函数,执行多次,返回值是一个id
  • 取消定时器
clearTimeout(id);  //取消由setTimeout方式开启的定时器
clearInterval(id);  //取消由setInterval方式开启的定时器
  • 原理分析:参见浏览器原理的「JS单线程引擎」
    本质就是,JS代码都是单线程执行的,利用 事件机制EventLoop + 任务回调队列 实现异步功能。

1、JSON对象和字符串互转

  • 由JSON字符串转换为JSON对象
var obj = str.parseJSON(); 
var obj = JSON.parse(str);
  • 将JSON对象转化为JSON字符串
var str=obj.toJSONString(); 
var str=JSON.stringify(obj);
  • 获取字典所有key和value
Object.keys(dic);
Object.values(dic);
  • uni-app 为什么不支持 new XMLHttpRequest() ?
    这是h5的专用api。
    非h5,不管是小程序还是app都没有window对象,要用uni.request。

0、数组、字典、字符串操作

字符串
  • 替换
var text = "Hello World!";
// 替换Hellow为123,g表示全局替换,i表示不区分大小写
var text = text.replace(/Hello/gi, '123');   

// 替换变量的值,只能使用正则
var ch = 'Hello';
var text = text.replace(RegExp(ch, 'gi'), '123'); 

// 转化
parseFloat(str);
parseInt(str)
数组操作
var list = ["haha", 1, 2, "你好"];
list.push("name"); // 添加新元素
list.pop(); // 删除最后一个元素
list.reverse(); // 倒叙

list.slice(1);  // 浅拷贝:截取从1位置之后的数组
var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = fruits.slice(1, 3);

list.indexOf('haha') ; // 返回对象数组下标

// 清空数组
var ary = [1,2,3,4]; 
ary.splice(0,ary.length);//清空数组 
console.log(ary); // 输出 [],空数组,即被清空了
浅拷贝 和 深拷贝
  • 默认的都是浅拷贝,如直接赋值,arr.slice、arr.concat等方法。
  • 深拷贝
    1、使用JSON.stringify和JSON.parse
    缺点:JSON.stringify()有一些局限,比如对于RegExp类型和Function类型则无法完全满足,而且不支持有循环引用的对象。
var newArr = JSON.parse(JSON.stringify(arr));

2、深拷贝的一个通用方法
实现思路:拷贝的时候判断属性值的类型,如果是对象,继续递归调用深拷贝函数

var deepCopy = function(obj) {
  // 只拷贝对象
  if (typeof obj !== 'object') return;
  // 根据obj的类型判断是新建一个数组还是一个对象
  var newObj = obj instanceof Array ? [] : {};
  for (var key in obj) {
    // 遍历obj,并且判断是obj的属性才拷贝
    if (obj.hasOwnProperty(key)) {
      // 判断属性值的类型,如果是对象递归调用深拷贝
      newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
    }
  }
  return newObj;
}


字典
// 更新和新值
var dic = {};
dic[key] = "name";

// 遍历
for (var key in dic) {
  var item = dic[key];
  console.log(item); 
}
其他
toFixed(1) //保留一位小数点

运算符|| 和 &&

image.png
image.png
关于宏 和 常量
  • 标准中,没有宏定义的概念:
    JavaScript是解释型语言,不需要编译器,因此就没有宏定义的概念(宏定义是在编译器的预处理进行替换的)。

  • 标准中,没有枚举的概念。
    1、使用字典模拟枚举概念

var Fruit = {
 orange : 1,
 banana : 2,
 peach : 3,
 strawberry : 4
};
console.log(Fruit.orange);

2、在TypeScript中支持枚举类型,关键字enum

// 下标从0开始
enum Color {Red, Green, Blue}

TypeScript 数据类型---枚举 (Enum)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容