js基础知识梳理

489 阅读8分钟

从问题入手

学习知识基础是关键。在此记录关键问题,不断丰富。仅供自己学习。

问题

  • js内存分几类?分别用来存放什么?
  • 全局作用域和私有作用域
  • 内存释放
  • 什么叫预解释?
  • 全局变量和私有变量
  • 函数执行基本顺序
  • 代码执行变量获取顺序
  • 解释闭包
  • this的指向
  • 前端常接触的设计模式
  • var n1 = new Number和var n2 = 1有什么不同?var a1 = new Array和var a2 = []有什么不同?
  • 解释一下js的原型链

  • js内存分几类?分别用来存放什么?

answer:js分为栈内存和堆内存

堆内存用来存放引用数据类型的具体内容,object类型存储key value;function类型用来存放函数内容的字符串

栈内存用来提供一个js代码执行的环境。全局作用域和私有作用域都属于栈内存。

  • 全局作用域和私有作用域?

answer:

全局作用域:浏览器一打开就创建,浏览器关闭时才销毁。 私有作用域:函数执行才产生私有作用域。

  • 内存释放?

answer:

堆内存释放:引用数据类型定义的时候开辟一个新的堆内存,该内存有个引用地址。如果存在变量引用该地址,则内存被占用不可销毁。若想释放,则把他的内存指向null,当前堆内存没有被占用,则浏览器会在空闲时销毁。

栈内存释放:全局作用域浏览器一打开即创建,关闭才销毁。私有作用域,函数执行时产生,私有作用域的代码执行完了,则当前作用域被销毁。

但是,当前私有作用域的部分内容被当前作用域之外的内容占用了,当前作用域不能销毁

  1. 函数执行返回一个引用数据类型的值,并且在函数外被接收了。这种情况行程的私有作用域不会被销毁,比如返回一个函数、对象、数组、则该堆内存无法释放,与此同时,执行该堆内存的执行栈内存也无法释放。但是返回数字,字符串,布尔值,则直接返回值,函数执行产生的私有作用域执行一次销毁一次。
  2. 私有作用域中进行dom事件绑定,因为dom事件绑定,则该私有作用域也不能释放(dom绑定相当于返回一个函数,和情况1本质相同)。
  3. 函数执行返回的函数并没有被其余变量接收,但是会紧接着执行一次,则该内存不会立即销毁,在执行完毕后再销毁。
function fn(){
    var num = 100;
    return function(){
        
    }
}
fn()()
  • 什么叫预解释?

answer:也叫变量提升。在当前作用域中,js代码执行之前,浏览器首先会把带var 和 function 的进行提前声明或定义。(var 声明 function 声明+定义)

预解释只发生在当前作用域下,开始只对window下(全局作用域)下预解释,函数执行时对(私有作用域)下进行预解释。全局和私有作用域都存在预解释。

  • 全局变量和私有变量?

answer:

全局变量:全局作用域下定义的变量(全局下预解释)

私有变量:私有作用域中声明的变量 和 函数的形参。

  • 函数执行基本顺序?

answer:

  1. 生成一个新的私有作用域
  2. 如果有形参,先形参赋值
  3. 在私有作用域中进行预解释
  4. 在私有作用域中从上到下执行代码
  • 函数执行变量获取顺序?

answer:

  1. 先确定私有变量中是否存在(形参+声明的私有变量),如果有优先使用私有变量。
  2. 如果没有则向上级作用域查找,直到window为止。
  3. 上级作用域只和函数定义有关,和在哪执行无关。在哪个作用域下定义的,上级作用域就是谁。
  • 解释闭包?

answer:闭包是一种机制,函数执行时产生的私有作用域内的变量保护起来,不受外界干扰。

  • this的指向?

answer:仅代表当前行为的执行主体

和的当前执行的环境(区域)上下文无关; 和函数在哪定义,在哪执行无关;

  1. 函数执行,函数名前面有.则.前面为this;没有.window为this;
  2. 自执行函数中,this永远指向window;
  3. 给dom元素绑定事件,当前事件触发执行绑定方法,方法中的this执行当前dom元素。
  4. 构造函数模式中,函数体中(类中)的this中,指向当前类的一个实例。
  • 前端常接触的设计模式 answer:
  1. 单例模式:分组编写各自的功能模块。
  2. 工厂模式:相同功能代码,抽取到一个函数处理。
  3. 构造函数模式:创建类,并利用类的实例。
function Fn(){
    this.x = 100;
}
Fn.prototype.getX = function(){};
var f1 = new Fn
构造函数模式注意点:
1. 不需要传参时,()可以省略。
2. 构造函数中的this指向某个实例,但是属性值内包含this,需要看.前面的内容。
function Fn(){
    this.x = 100;
    this.getX = function(){
        console.log(this.x)
    }
}
var f1 = new Fn
3. 构造函数里的var只是私有变量而已,和类、实例无关。
4. 构造函数模式中,**浏览器默认把实例返回**,返回一个**对象数据类型**的值。如果自己在构造函数中写return。return 基本数据类型的值,则当前实例不变。若return 引用数据类型,则当前实例为该引用数据类型。
function Fn(){
    this.x = 100;
    return [1,2,3]
}
var f1 = new Fn;
console.log(f1); // [1, 2, 3]
  1. 原型链模式:在构造函数基础上,解决属性共有问题。
  • var n1 = new Number和var n2 = 1有什么不同?var a1 = new Array和var a2 = []有什么不同?

answer:

new的形式是实例创建方式,n=1是对象字面量方式。前者是标准创建实例的方式。第二种是js弱类型语言独有的创建实例的方式。

针对引用数据类型:对象字面量,和类实例方式创建没有不同。 针对基本数据类型:两者不同。

var n1 = new Number(1);
var n2 = 1;
typeof(n1) // object
typeof(n2) //number
n1 instanceOf Number //true
n2 instanceOf number // false
  • 解释一下js的原型链

答:

* 所有函数数据类型,都自带一个prototype属性,存储值为对象数据类型,浏览器默认开辟一个堆内存
* prototype在浏览器环境下,拥有一个constructor属性,指向当前类本身
* 每个对象数据类型(普通对象,数组,正则,实例,prototype,函数),也天生自带一个属性__proto__。指向`当前实例所属类的原型(prototype)`
  • 类的私有属性(方法)和公有属性(或方法)分别在哪定义?

答:

私有写到函数体中,this.的形式定义 公有写到prototye原型链中

  • 详细列出div元素;a元素;document;window的原型链?

答: 为什么div元素有getElementsByClassName;但是却没有getElementById

  • 一个函数的多面性

答: 所有函数数据类型都是Function类的实例 所有类都是函数 每个函数都是Object类的实例

1、普通函数 执行的时候形成私有作用域(闭包) 形参赋值 预解释 代码执行,执行完成后栈内存销毁or被占用而不能销毁 2、类 他有自己的实例,也有一个prototype属性指向原型 3、普通对象: 可以有自己私有属性(name,length,等等),也有__proto__指向Funtion的prototype 三者没有必然联系,每种角色,不混用!!!

特殊记忆: Function.prototype是函数数据类型的,但是相关操作和对象一模一样。-->anonymous(匿名函数)

  • call的作用

call是存在于Function.prototype上的属性方法

call的作用在于:改变this关系

call执行:1)让fn中this变为obj ;2)再把fn中的内容执行完成。

概念化call原理如下:

// Function.prototype.call = mycall function (context) {
    // 1、让fn中this 关键字变成context的值
    // eval(this.toString().replace('this', 'context'));
    // 2、让fn执行
    // this();
// }
   // call 方法执行
   obj = {};
   fn.call(obj)

call的测试题,如下四个输出结果

function fn1() {
    console.log(1);
}

function fn2() {
    console.log(2);
}
fn1.call(fn2); 
fn1.call.call(fn2); 
Function.prototype.call(fn1);
Function.prototype.call.call(fn1);

结果:

1;2;undefined;1;

Function.prototype.call(fn1);// Function.prototype为空函数,this指向fn1,空函数执行,得到undefined

  • 严格模式和非严格模式下call执行的不同点
"use strict"
function fn(num1, num2) {
    console.log(num1 + num2);
    console.log(this);
}
var obj = {
    'key': 'value'
};
fn(100, 200);
fn.call(100, 200);
fn.call(obj, 100, 200);
fn.call(); // this->window  严格模式下 undefined
fn.call(null); // this->window 严格模式下 null
fn.call(undefined); // this->window 严格模式下 undefined

从使用角度来看,由于严格模式和非严格模式下this指向null的表现不尽相同。所以尽量不要指向null或者undefined。根据环境浏览器就写window。node环境就写global。

  • call apply bind 三者之间关系

call,apply作用相同,包含改变this指向+执行。不同的是,call接收参数,apply接收数组作为参数。

bind,预先改变this执行,但不执行。预处理的性质。ie6-8不兼容