# [js] 简单介绍一下DOM 跟BOM?

DOM 代表文档对象模型,是 HTML 和 XML 文档的接口(API)。当浏览器第一次读取(解析)HTML文档时,它会创建一个大对象,一个基于 HTM L文档的非常大的对象,这就是DOM。它是一个从 HTML 文档中建模的树状结构。DOM 用于交互和修改DOM结构或特定元素或节点。

javascript中数据类型、对象属性?

最新的 ECMAScript 标准定义了 8 种数据类型:

7 种原始类型 (基本类型)

  • Boolean
  • Null
  • Undefined
  • Number
  • BigInt BigInt类型是 js 中的一个基础的数值类型,可以用任意精度表示整数,操作大整数。 BigInt是通过在整数末尾附加 n或调用构造函数来创建的。
  • String
  • Symbol 符号类型是唯一的并且是不可修改的, 并且也可以用来作为Object的key的值

和 Object 对象类型(引用类型)

  • ECMAScript定义的对象中有两种属性:数据属性和访问器属性。

  • 判断Array跟object:

    var a = []; 
    // 1.基于instanceof 
    a instanceof Array; 
    // 2.基于constructor 
    a.constructor === Array; 
    // 3.基于Object.prototype.isPrototypeOf 
    Array.prototype.isPrototypeOf(a); 
    // 4.基于getPrototypeOf 
    Object.getPrototypeOf(a) === Array.prototype; 
    // 5.基于Object.prototype.toString 
    Object.prototype.toString.apply(a) === '[object Array]';
    // 6.ES6 isArray()
    Array.isArray([]); // => true 
    Array.isArray({0: 'a', length: 1}); // => false
    
    //判断数组最佳写法
    var arr = [1,2,3,1]; 
    var arr2 = [{ abac : 1, abc : 2 }]; 
    function isArrayFn(value){ 
        if (typeof Array.isArray === "function") { 
            return Array.isArray(value); 
        }else{ 
            return Object.prototype.toString.call(value) === "[object Array]"; 
        } 
    } 
    alert(isArrayFn(arr));     // true 
    alert(isArrayFn(arr2));    // true 
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27

# [js] 什么是事件传播?

事件发生在DOM元素上时,该事件并不完全发生在那个元素上。 在**“冒泡阶段”中,事件冒泡或向上传播至父级,祖父母,祖父母或父级,直到到达window为止;而在“捕获阶段”**中,事件从window开始向下触发元素 事件或event.target

事件传播有三个阶段:

  1. 捕获阶段–事件从 window 开始,然后向下到每个元素,直到到达目标元素。
  2. 目标阶段–事件已达到目标元素。
  3. 冒泡阶段–事件从目标元素冒泡,然后上升到每个元素,直到到达 window

event.preventDefault() 方法可防止元素的默认行为。 如果在表单元素中使用,它将阻止其提交。 如果在锚元素中使用,它将阻止其导航。 如果在上下文菜单中使用,它将阻止其显示或显示。

event.stopPropagation()方法用于阻止捕获和冒泡阶段中当前事件的进一步传播。

# [js] == 和 === 有什么区别?

==用于一般比较,===用于严格比较,==在比较的时候可以转换数据类型,===严格比较,只要类型不匹配就返回flase

先来看看 == 这兄弟:

强制是将值转换为另一种类型的过程。 在这种情况下,==会执行隐式强制。 在比较两个值之前,==需要执行一些规则。

假设我们要比较x == y的值。

  1. 如果xy的类型相同,则 JS 会换成===操作符进行比较。
  2. 如果xnull, yundefined,则返回true
  3. 如果xundefinedynull,则返回true
  4. 如果x的类型是number, y的类型是string,那么返回x == toNumber(y)
  5. 如果x的类型是string, y的类型是number,那么返回toNumber(x) == y
  6. 如果x为类型是boolean,则返回toNumber(x)== y
  7. 如果y为类型是boolean,则返回x == toNumber(y)
  8. 如果xstringsymbolnumber,而yobject类型,则返回x == toPrimitive(y)
  9. 如果xobjectystringsymbol则返回toPrimitive(x) == y
  10. 剩下的 返回 false

注意:toPrimitive首先在对象中使用valueOf方法,然后使用toString方法来获取该对象的原始值。

举个例子。

x y x == y
5 5 true
1 '1' true
null undefined true
0 false true
'1,2' [1,2] true
'[object Object]' {} true

这些例子都返回true

第一个示例符合条件1,因为xy具有相同的类型和值。

第二个示例符合条件4,在比较之前将y转换为数字。

第三个例子符合条件2

第四个例子符合条件7,因为yboolean类型。

第五个示例符合条件8。 使用toString()方法将数组转换为字符串,该方法返回1,2

最后一个示例符合条件8。 使用toString()方法将对象转换为字符串,该方法返回[object Object]

x y x === y
5 5 true
1 '1' false
null undefined false
0 false false
'1,2' [1,2] false
'[object Object]' {} false

如果使用===运算符,则第一个示例以外的所有比较将返回false,因为它们的类型不同,而第一个示例将返回true,因为两者的类型和值相同。

# [js] 严格模式 'use strict'

"use strict"ES5 特性,它使我们的代码在函数或整个脚本中处于严格模式严格模式帮助我们在代码的早期避免 bug,并为其添加限制。

  • 严格模式的一些限制:
  1. 变量必须声明后再使用
  2. 函数的参数不能有同名属性,否则报错
  3. 不能使用with语句
  4. 不能对只读属性赋值,否则报错
  5. 不能使用前缀 0 表示八进制数,否则报错
  6. 不能删除不可删除的属性,否则报错
  7. 不能删除变量delete prop,会报错,只能删除属性delete global[prop]
  8. eval不能在它的外层作用域引入变量
  9. evalarguments不能被重新赋值
  10. arguments不会自动反映函数参数的变化
  11. 不能使用arguments.callee
  12. 不能使用arguments.caller
  13. 禁止this指向全局对象
  14. 不能使用fn.callerfn.arguments获取函数调用的堆栈
  15. 增加了保留字(比如protectedstaticinterface
  • 设立”严格模式”的目的,主要有以下几个:
  1. 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
  2. 消除代码运行的一些不安全之处,保证代码运行的安全;
  3. 提高编译器效率,增加运行速度;
  4. 为未来新版本的Javascript做好铺垫。

# [js] Function.prototype.apply 方法的用途是什么?

apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。

const details = {
  message: 'Hello World!'
};

function getMessage(){
  return this.message;
}

getMessage.apply(details); // 'Hello World!'
1
2
3
4
5
6
7
8
9

call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。

const person = {
  name: "Marko Polo"
};

function greeting(greetingMessage) {
  return `${greetingMessage} ${this.name}`;
}

greeting.apply(person, ['Hello']); // "Hello Marko Polo!"
1
2
3
4
5
6
7
8
9

# [js] Function.prototype.call 方法的用途是什么?

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

const details = {
  message: 'Hello World!'
};

function getMessage(){
  return this.message;
}

getMessage.call(details); // 'Hello World!'
1
2
3
4
5
6
7
8
9

注意:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组。

const person = {
  name: "Marko Polo"
};

function greeting(greetingMessage) {
  return `${greetingMessage} ${this.name}`;
}

greeting.call(person, 'Hello'); // "Hello Marko Polo!"
1
2
3
4
5
6
7
8
9

# [js] Function.prototype.bind 的用途是什么?

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

import React from 'react';

class MyComponent extends React.Component {
     constructor(props){
          super(props); 
          this.state = {
             value : ""
          }  
          this.handleChange = this.handleChange.bind(this); 
          // 将 “handleChange” 方法绑定到 “MyComponent” 组件
     }

     handleChange(e){
       //do something amazing here
     }

     render(){
        return (
              <>
                <input type={this.props.type}
                        value={this.state.value}
                     onChange={this.handleChange}                      
                  />
              </>
        )
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# [js] arguments 的对象是什么?

arguments对象是函数中传递的参数值的集合。它是一个类似数组的对象,因为它有一个length属性,我们可以使用数组索引表示法arguments[1]来访问单个值,但它没有数组中的内置方法,如:forEachreducefiltermap

我们可以使用Array.prototype.slicearguments对象转换成一个数组。

function one() {
  return Array.prototype.slice.call(arguments);
}
1
2
3

注意:箭头函数中没有arguments对象。

function one() {
  return arguments;
}
const two = function () {
  return arguments;
}
const three = function three() {
  return arguments;
}

const four = () => arguments;

four(); // Throws an error  - arguments is not defined
1
2
3
4
5
6
7
8
9
10
11
12
13

当我们调用函数four时,它会抛出一个ReferenceError: arguments is not defined error。使用rest语法,可以解决这个问题。

const four = (...args) => args;
1

这会自动将所有参数值放入数组中。

# [js] ES6或ECMAScript 2015有哪些新特性?

  • 箭头函数
  • 模板字符串
  • 加强的对象字面量
  • 对象解构
  • Promise
  • 生成器
  • 模块
  • Symbol
  • 代理
  • Set
  • 函数默认参数
  • rest 和展开
  • 块作用域

# [js] 什么是对象解构?

对象析构是从对象或数组中获取或提取值的一种新的、更简洁的方法。假设有如下的对象:

const employee = {
  firstName: "Marko",
  lastName: "Polo",
  position: "Software Developer",
  yearHired: 2017
};
1
2
3
4
5
6

从对象获取属性,早期方法是创建一个与对象属性同名的变量。这种方法很麻烦,因为我们要为每个属性创建一个新变量。假设我们有一个大对象,它有很多属性和方法,用这种方法提取属性会很麻烦。

var firstName = employee.firstName;
var lastName = employee.lastName;
var position = employee.position;
var yearHired = employee.yearHired;
1
2
3
4

使用解构方式语法就变得简洁多了:

{ firstName, lastName, position, yearHired } = employee;
1

我们还可以为属性取别名:

let { firstName: fName, lastName: lName, position, yearHired } = employee;
1

当然如果属性值为 undefined 时,我们还可以指定默认值:

let { firstName = "Mark", lastName: lName, position, yearHired } = employee;
1

# [js] Promise 是什么?

Promise 是异步编程的一种解决方案:从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。promise有三种状态:pending(等待态)fulfiled(成功态)rejected(失败态);状态一旦改变,就不会再变。创造promise实例后,它会立即执行。

fs.readFile('somefile.txt', function (e, data) {
  if (e) {
    console.log(e);
  }
  console.log(data);
});
1
2
3
4
5
6

如果我们在回调内部有另一个异步操作,则此方法存在问题。 我们将有一个混乱且不可读的代码。 此代码称为**“回调地狱”**。

// 回调地狱
fs.readFile('somefile.txt', function (e, data) { 
  //your code here
  fs.readdir('directory', function (e, files) {
    //your code here
    fs.mkdir('directory', function (e) {
      //your code here
    })
  })
})
1
2
3
4
5
6
7
8
9
10

如果我们在这段代码中使用promise,它将更易于阅读、理解和维护。

promReadFile('file/path')
  .then(data => {
    return promReaddir('directory');
  })
  .then(data => {
    return promMkdir('directory');
  })
  .catch(e => {
    console.log(e);
  })
1
2
3
4
5
6
7
8
9
10

promise有三种不同的状态:

  • pending:初始状态,完成或失败状态的前一个状态
  • fulfilled:操作成功完成
  • rejected:操作失败

pending 状态的 Promise 对象会触发 fulfilled/rejected 状态,在其状态处理方法中可以传入参数/失败信息。当操作成功完成时,Promise 对象的 then 方法就会被调用;否则就会触发 catch。如:

const myFirstPromise = new Promise((resolve, reject) => {
    setTimeout(function(){
        resolve("成功!"); 
    }, 250);
});

myFirstPromise.then((data) => {
    console.log("Yay! " + data);
}).catch((e) => {...});
1
2
3
4
5
6
7
8
9

# [js] async await 是什么?

async/await是 JS 中编写异步或非阻塞代码的新方法。它建立在Promises之上,让异步代码的可读性和简洁度都更高。

async/await是 JS 中编写异步或非阻塞代码的新方法。 它建立在Promises之上,相对于 Promise 和回调,它的可读性和简洁度都更高。 但是,在使用此功能之前,我们必须先学习Promises的基础知识,因为正如我之前所说,它是基于Promise构建的,这意味着幕后使用仍然是Promise

使用 Promise

function callApi() {
  return fetch("url/to/api/endpoint")
    .then(resp => resp.json())
    .then(data => {
      //do something with "data"
    }).catch(err => {
      //do something with "err"
    });
}
1
2
3
4
5
6
7
8
9

使用async/await

async/await,我们使用 tru/catch 语法来捕获异常。

async function callApi() {
  try {
    const resp = await fetch("url/to/api/endpoint");
    const data = await resp.json();
    //do something with "data"
  } catch (e) {
    //do something with "err"
  }
}
1
2
3
4
5
6
7
8
9

注意:使用 async关键声明函数会隐式返回一个Promise

const giveMeOne = async () => 1;

giveMeOne()
  .then((num) => {
    console.log(num); // logs 1
  });
1
2
3
4
5
6

注意:await关键字只能在async function中使用。在任何非async function的函数中使用await关键字都会抛出错误。await关键字在执行下一行代码之前等待右侧表达式(可能是一个Promise)返回。

const giveMeOne = async () => 1;

function getOne() {
  try {
    const num = await giveMeOne();
    console.log(num);
  } catch (e) {
    console.log(e);
  }
}

// Uncaught SyntaxError: await is only valid in async function

async function getTwo() {
  try {
    const num1 = await giveMeOne(); // 这行会等待右侧表达式执行完成
    const num2 = await giveMeOne(); 
    return num1 + num2;
  } catch (e) {
    console.log(e);
  }
}

await getTwo(); // 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# [js] 如何检查对象中是否存在某个属性?

检查对象中是否存在属性有三种方法。

第一种使用 in 操作符号:

const o = { 
  "prop" : "bwahahah",
  "prop2" : "hweasa"
};

console.log("prop" in o); // true
console.log("prop1" in o); // false
1
2
3
4
5
6
7

第二种使用 hasOwnProperty 方法,hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。

console.log(o.hasOwnProperty("prop2")); // true
console.log(o.hasOwnProperty("prop1")); // false
1
2

第三种使用括号符号obj["prop"]。如果属性存在,它将返回该属性的值,否则将返回undefined

console.log(o["prop"]); // "bwahahah"
console.log(o["prop1"]); // undefined
1
2

# [js]in 运算符和 Object.hasOwnProperty 方法有什么区别?

hasOwnPropert方法

hasOwnPropert()方法返回值是一个布尔值,指示对象自身属性中是否具有指定的属性,因此这个方法会忽略掉那些从原型链上继承到的属性。

看下面的例子:

Object.prototype.phone= '15345025546';

let obj = {
	name: '前端小智',
	age: '28'
}
console.log(obj.hasOwnProperty('phone')) // false
console.log(obj.hasOwnProperty('name')) // true
1
2
3
4
5
6
7
8

可以看到,如果在函数原型上定义一个变量phonehasOwnProperty方法会直接忽略掉。

in 运算符

如果指定的属性在指定的对象或其原型链中,则in 运算符返回true

还是用上面的例子来演示:

console.log('phone' in obj) // true
1

可以看到in运算符会检查它或者其原型链是否包含具有指定名称的属性。

# [js] js中的强制转换规则

toString

Object.prototype.toString()

toString()方法返回一个表示该对象的字符串。

每个对象都有一个 toString() 方法,当对象被表示为文本值时或者当以期望字符串的方式引用对象时,该方法被自动调用。

这里先记住,valueOf()toString()在特定的场合下会自行调用。

valueOf

Object.prototype.valueOf()方法返回指定对象的原始值。

JavaScript 调用 valueOf() 方法用来把对象转换成原始类型的值(数值、字符串和布尔值)