Js基础类待扩展

139 阅读5分钟

对象

1、计算属性

创建对象时,可以在对象字面中使用方括号,即计算属性

  let key = "name";
  let inputKey = prompt("请输入key", "age");
  let user = { [key] : "leo", [inputKey] : 18}// 当用户在 prompt 上输入 "age" 时,user 变成下面样子:

// {name: "leo", age: 18}
// prompt() 方法用于显示可提示用户进行输入的对话框。
prompt(text, defaultText)

2、对象属性存在性检测

(1)使用in关键字,用于判断对象的自有属性和继承属性是否存在

  let user = {name: "leo"};
  "name" in user; //true,自有属性存在
  "age" in user; //false
  "toString" in user; //true,是一个继承属性

(2)使用hasOwnProperty,只能判断自有属性是否存在,对于继承属性会显示false

  let user = {name: "leo"};
  user.hasOwnProperty("name"); //true,自有属性中有 
  nameuser.hasOwnProperty("age"); //false,自有属性中不存在 			   ageuser.hasOwnProperty("toString"); //false,这是一个继承属性,但不是自有属性

(3)undefined可以判断自有属性和继承属性是否存在,但如果属性值是undefined,则返回不是想要的结果

  let user = {name: "leo"};
  user.name !== undefined; // true
  user.age !== undefined; // false
  user.toString !== undefined // true
  let user = {name: undefined};
  user.name !== undefined; // false,属性存在,但值是undefined
  user.age !== undefined; // false
  user.toString !== undefined; // true

(4)在条件语句中判断

  let user = {};
  if(user.name) user.name = "pingan";
  //如果 name 是 undefine, null, false, " ", 0 或 NaN,它将保持不变
user; // {}

(5)typeof可检测出 number,string,boolean,object,undefined,function

  typeof(null)//object 
  typeof(NaN)//object 
  typeof(undefined)//undefined
  typeof(类型名)//string

封装typeof

 function myTypeof(val){
    var type = typeof(val),
        toStr = Object.prototype.toString,
        res = {
            '[object Array]' : 'array',
            '[object Object]' : 'object',
            '[object Number]' : 'object number',
            '[object String]' : 'object string',
            '[object Boolean]' : 'object boolean'
        };
    if(val === null){
        return 'null'
    }else if(type === 'object'){
        var ret = toStr.call(val);
        return res[ret];
    }else{
        return type;
    }
}

3、 对象循环遍历

用for…in实现遍历对象中的每一个属性,除symbol可枚举属性之外

  let user = {
    name : "leo",
    age : 18
  }
  for(let k in user){
	console.log(k, user[k]);
  }
	// name leo
	// age 18

4、 ES7新增方法

(1)、object.keys()返回一个数组,成员是参数对象自身的所有可遍历属性的键名

let user = { name: "leo", age: 18};
Object.keys(user); // ["name", "age"]

(2)、object.values()返回一个数组,成员是参数对象自身的所有可遍历属性的键值,如果参数不是对象,则返回空数组

(3)、object.entries()返回一个数组,成员是参数对象自身的所有可遍历的键值对数组

let user = { name: "leo", age: 18};
Object.entries(user);// [["name","leo"],["age",18]]   

(4)、getOwnPropertyNames()返回一个数组,包含了参数对象所有属性的名称

let user = { name: "leo", age: 18};
Object.getOwnPropertyNames(user);// ["name", "age"]

对象拷贝

浅拷贝:只对第一层属性进行拷贝(一个新的对象直接拷贝已存在对象的属性的引用),当第一层的属性值是基本数据类型时,新的对象和原对象互不影响,但是如果第一层的属性值是复杂数据类型,那么新对象和原对象的属性值其指向的是同一块内存地址。

  1. 实现浅拷贝
Object.assign(target, ...source)
   // 示例1 对象浅拷贝
	let user = { name: "leo", skill: { JavaScript: 90, CSS: 80}};
	let leo = Object.assign({}, user);
	leo.name = "leo1";
	leo.skill.CSS = 90;
	console.log(leo.name); // "leo1" 
	console.log(user.name); // "leo" 
	console.log(leo.skill.CSS); // 90
	console.log(user.skill.CSS);// 90

// 示例2 数组深拷贝

  let user = ["leo", "pingan", {name: "pingan8787"}];
  let leo = user;
  leo[0] = "pingan888";
  leo[2]["name"] = "pingan999";
  console.log(leo[0]); // "pingan888" ⚠️ 差异!
  console.log(user[0]); // "leo" ⚠️ 差异!
  console.log(leo[2]["name"]); // "pingan999"
  console.log(user[2]["name"]); // "pingan999"

Object.assign() 使用注意:

只拷贝源对象的自身属性(不拷贝继承属性);

不会拷贝对象不可枚举的属性;

属性名为Symbol 值的属性,可以被Object.assign拷贝;

undefined和null无法转成对象,它们不能作为Object.assign参数,但是可以作为源对象。

Object.assign(undefined); // 报错
Object.assign(null); // 报错
Object.assign({}, undefined); // {}
Object.assign({}, null); // {}
let user = {name: "leo"};
Object.assign(user, undefined) === user; // true
Object.assign(user, null) === user; // true
Array.prototype.concat()
Array.prototype.slice()

拓展运算符(...)

var cloneObj = { ...obj }
let user = { name: "leo", skill: { JavaScript: 90, CSS: 80}};
let leo = {...user};
leo.name = "leo1";
leo.skill.CSS = 90;
console.log(leo.name); // "leo1" 差异!
console.log(user.name); // "leo" 差异!
console.log(leo.skill.CSS); // 90
console.log(user.skill.CSS);// 90

手写浅拷贝

function cloneShallow(source) {
  let target = {};
  for (let key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      target[key] = source[key];
    }
  }
  return target;
}
  1. 实现深拷贝 JSON.parse(JSON.stringfy()) 其原理是把一个对象序列化成为一个JSON字符串,将对象的内容转换成字符串的形式再保存在磁盘上,再用JSON.parse() 反序列化将JSON字符串变成一个新的对象。
let user = { name: "leo", skill: { JavaScript: 90, CSS: 80}};
let leo = JSON.parse(JSON.stringify(user));
leo.name = "leo1";
leo.skill.CSS = 90;
console.log(leo.name); // "leo1" 
console.log(user.name); // "leo" 
console.log(leo.skill.CSS); // 90 
console.log(user.skill.CSS);// 80 

第三方库,lodash 手写深拷贝

const isObject = obj => typeof obj === 'object' && obj != null;
function cloneDeep(source) {
  if (!isObject(source)) return source; // 非对象返回自身
  const target = Array.isArray(source) ? [] : {};
  for(var key in source) {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      if (isObject(source[key])) {
      	target[key] = cloneDeep(source[key]); // 注意这里
      } else {
      	target[key] = source[key];
      }
    }
  }
  return target;
}

原始值转换

需要记住几个规则:

1、所有对象在布尔上下文中都为 true ,并且不存在转换为布尔值的操作,只有字符串和数值转换有。

2、数值转换发生在对象相减或应用数学函数时。如 Date 对象可以相减,如 date1 - date2 结果为两个时间的差值。

3、在字符串转换,通常出现在如 alert(obj) 这种形式。

Event Loop

进程与线程

涉及面试题:进程与线程区别?JS 单线程带来的好处?

进程:指在系统中正在运行的一个应用程序;程序一旦运行就是进程;进程——资源分配的最小单位。

线程:系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元执行流。 线程——程序执行的最小单位。

区别:

1.进程要分配一大部分的内存,而线程只需要分配一部分栈就可以了;

2.一个程序至少有一个进程,一个进程至少有一个线程;

3.进程是资源分配的最小单位,线程是程序执行的最小单位;

4.一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。

涉及面试题:什么是执行栈?

可以把执行栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。