JS

JavaScript基础整理(一)

2020-03-20  本文已影响0人  肉桂猿

数据类型
null 和 undefined
== 和 ===
JS 比较对象和基本类型
!! 运算符
JavaScript 中的虚值
一行中计算多个表达式的值
作用域
作用域链
什么是提升
this指针
IIFE
new操作符
事件流
addEventListener
event.preventDefault() 和 event.stopPropagation()
event.target 和 event.currentTarget
闭包 Closure


基本数据类型存储在栈中,占据空间小、大小固定,属于被频繁使用数据;
引用数据类型存储在堆中,指针放在栈中。占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。


  1. 属于JS基本类型。
let primitiveTypes = ['string','number','null','undefined','boolean','symbol', 'bigint'];
  1. 是虚值,可以使用Boolean(value)!!value将其转换为布尔值时,值为false。
console.log(!!null); // false
console.log(!!undefined); // false

console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false

区别 -
null是“不代表任何值的值”。null是已明确定义给变量的值。表示一个对象被定义了,但存放了空指针,转换为数值时为0
undefined是未指定特定值的变量的默认值,或者没有显式返回值的函数,如:console.log(1),还包括对象中不存在的属性,这些 JS 引擎都会为其分配 undefined 值。,转换为数值时为NAN

typeof(null) -- object;
typeof(undefined) -- undefined
console.log(null == undefined); // true
 console.log(null === undefined); // false

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

如果x和y的类型相同,则 JS 会换成===操作符进行比较。
如果x为null, y为undefined,则返回true。
如果x为undefined且y为null,则返回true。
如果x的类型是number, y的类型是string,那么返回x == toNumber(y)。
如果x的类型是string, y的类型是number,那么返回toNumber(x) == y。
如果x为类型是boolean,则返回toNumber(x)== y。
如果y为类型是boolean,则返回x == toNumber(y)。
如果x是string、symbol或number,而y是object类型,则返回x == toPrimitive(y)。
如果x是object,y是string,symbol则返回toPrimitive(x) == y。
剩下的 返回 false

let a = { a: 1 };
let b = { a: 1 };
let c = a;

console.log(a === b); // 打印 false,即使它们有相同的属性
console.log(a === c); // true

console.log(!!null); // false
console.log(!!undefined); // false
console.log(!!''); // false
console.log(!!0); // false
console.log(!!NaN); // false
console.log(!!' '); // true
console.log(!!{}); // true
console.log(!![]); // true
console.log(!!1); // true
console.log(!![].length); // false

const falsyValues = ['', 0, null, undefined, NaN, false];

简单的来说虚值就是是在转换为布尔值时(使用 Boolean 函数或者 !! 运算符)变为 false 的值。


let x = 5;
x = (x++ , x = addFive(x), x *= 2, x -= 5, x += 10);
function addFive(num) {
  return num + 5;
}

  1. 全局作用域——在全局命名空间中声明的变量或函数位于全局作用域中,因此在代码中的任何地方都可以访问它们。
  2. 函数作用域——在函数中声明的变量、函数和参数可以在函数内部访问,但不能在函数外部访问。
  3. 块作用域-在块{}中声明的变量(letconst)只能在其中访问。


编译-在此阶段,JS 引荐获取所有函数声明并将其提升到其作用域的顶部,以便我们稍后可以引用它们并获取所有变量声明(使用var关键字进行声明),还会为它们提供默认值:undefined。

执行——在这个阶段中,它将值赋给之前提升的变量,并执行或调用函数(对象中的方法)。

注意:只有使用var声明的变量,或者函数声明才会被提升,相反,函数表达式或箭头函数,let和const声明的变量,这些都不会被提升。

console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));

function greet(name){
  return 'Hello ' + name + '!';
}

var y;

上面分别打印:undefined,1, Hello Mark!
上面代码在编译阶段其实是这样的:

function greet(name) {
  return 'Hello ' + name + '!';
}

var y; // 默认值 undefined

// 等待“编译”阶段完成,然后开始“执行”阶段

/*
console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));
*/

编译阶段完成后,它将启动执行阶段调用方法,并将值分配给变量。

function greet(name) {
  return 'Hello ' + name + '!';
}

var y;

//start "execution" phase

console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));

  1. this总是指向函数的直接调用者(而非间接调用者)
  2. 如果有new关键字,this指向new出来的那个对象
  3. 在事件中,this指向目标元素,特殊的是IE的attachEvent中的this总是指向全局对象window
    this指的是当前正在执行或调用该函数的对象的值。this值的变化取决于我们使用它的上下文和我们在哪里使用它。
const carDetails = {
  name: "Ford Mustang",
  yearBought: 2005,
  getName(){
    return this.name;
  },
  isRegistered: true
};

console.log(carDetails.getName()); // Ford Mustang

这通常是我们期望结果的,因为在getName方法中我们返回this.name,在此上下文中,this指向的是carDetails对象,该对象当前是执行函数的“所有者”对象。
接下我们做些奇怪的事情:

var name = "Ford Ranger";
var getCarName = carDetails.getName;

console.log(getCarName()); // Ford Ranger

在全局作用域中使用var关键字声明变量会在window对象中附加与变量名称相同的属性。
解决这个问题的一种方法是在函数中使用applycall方法。applycall方法期望第一个参数是一个对象,该对象是函数内部this的值。

console.log(getCarName.apply(carDetails)); // Ford Mustang
console.log(getCarName.call(carDetails));  // Ford Mustang

(function(){
  ...
} ());

(function () {
  ...
})();

(function named(params) {
  ...
})();

(() => {
});

(function (global) {
  ...
})(window);

const utility = (function () {
  return {
    ...
  }
})

经典面试题目:

var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
   (function (currentIndex) {
      li[currentIndex].addEventListener('click', function (e) {
         console.log(currentIndex);
      })
   })(i);
}

IIFE会为每次迭代创建一个新的作用域,我们捕获i的值并将其传递给currentIndex参数,因此调用IIFE时,每次迭代的currentIndex值都是不同的。


  1. 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
  2. 属性和方法被加入到 this 引用的对象中。
  3. 新创建的对象由 this 所引用,并且最后隐式的返回 this


el.addEventListener(event, callback, isCapture);


<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
    <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
        <div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
          <button style="margin:10px">
             Button
          </button>
        </div>
    </div>
 </div>
function clickFunc(event) {
  console.log(event.target);// 打印 button 标签
console.log(event.currentTarget);// 打印最外面的div标签
}

image.png
image.png
上一篇 下一篇

猜你喜欢

热点阅读