您当前的位置: 首页 >  Java

止步前行

暂无认证

  • 0浏览

    0关注

    247博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

JavaScript深入学习笔记

止步前行 发布时间:2021-08-27 16:20:07 ,浏览量:0

基础知识点深入 1. 数据类型

七种数据类型口诀:

USONB you are so niubility(JavaScript七种数据类型)

U undefined

S string symbol

O object

N null number

B boolean

基本(值)类型

基本数据类型数值判断方法Number任意数值typeofString任意字符串typeofBooleantrue/falsetypeofundefinedundefinedtypeof / ===nullnull===

注:typeof 返回数据类型的字符串表达

undefined、null两个类型只有一个值。

var a
console.log(a, typeof a, typeof a==='undefined',a===undefined )  
// undefined 'undefined' true true

对象(引用)类型

对象(引用)类型判断方法Objecttypeof/instanceofArrayinstanceofFunctiontypeof

Array是一种特别的对象,它的属性是数值下标,内部数据是有序的

Function是一种特别的对象,Function可以执行,但普通Object对象不行

强调:

  • typeof:可以判断: undefined / 数值 / 字符串 / 布尔值 / function

    不能判断: null与object object与array

    var a = null

    console.log(typeof a, a===null) // typeof a 的返回值为 ‘object’

  • instanceof:判断对象的具体类型

  • ===:可以判断: undefined,null

var b1 = {
    b2: [1, 'abc', console.log],
    b3: function () {
        console.log('b3')
        return function () {
            return 'xfzhang'
        }
    }
}

console.log(b1 instanceof Object, b1 instanceof Array) // true  false
console.log(b1.b2 instanceof Array, b1.b2 instanceof Object) // true true
console.log(b1.b3 instanceof Function, b1.b3 instanceof Object) // true true
console.log(typeof b1.b2, '-------') // 'object'
console.log(typeof b1.b3==='function') // true

相关问题:

  1. undefined与null的区别?
  • undefined 代表定义未赋值
  • null 定义并赋值了,只是值为null
  1. 什么时候给变量赋值为null呢?
  • 初始赋值,表明将要赋值为对象
  • 结束前,让对象成为垃圾对象(被垃圾回收器回收)
2. 对象

如何访问对象内部数据?

  • .属性名:编码简单,有时不能用
  • [‘属性名’]:编码麻烦,能通用
//1. 给p对象添加一个属性: content type: text/json
// p.content-type = 'text/json' // 不能用,报错
p['content-type'] = 'text/json'
console.log(p['content-type'])

//2. 属性名不确定
var propName = 'myAge'
var value = 18
// p.propName = value //不能用,报错
p[propName] = value
console.log(p[propName])
3. 函数

如何调用函数?

  • test():直接调用
  • obj.test():通过对象调用
  • new test():new调用
  • test.call(obj)或test.apply(obj):临时让test成为obj的方法进行调用(可以让一个函数成为指定任意对象的方法进行调用)
var obj = {}
function test () {
    this.xxx = 'scorpios'
}
// obj.test()  不能直接, 根本就没有test方法
test.call(obj) // 相当于 obj.test() 
console.log(obj.xxx)
test.apply(obj) 
console.log(obj.xxx)
  • 函数也是对象

    • instanceof Object === true
    • 函数有属性:prototype
    • 函数有方法:call()/apply()
    • 可以添加新的属性/方法
  • 函数中的this()

    • 显式指定谁:obj.xxx()
    • 通过call/apply指定谁调用:xxx.call(obj)
    • 不指定谁调用:xxx() : window
    • 回调函数:看背后是通过谁来调用的:window/其它

    注:任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window

  • 匿名函数自调用:

    (function(w, obj){
      //实现代码
    })(window, obj)
    

    专业术语为: IIFE (Immediately Invoked Function Expression) 立即调用函数表达式

    IIFE的作用:1、隐藏实现 2、不会污染外部(全局)命名空间 3、用它来编码js模块

  • 回调函数的理解,什么函数才是回调函数?

    满足三个条件:1、你定义的 2、你没有调用 3、但它最终执行了(在一定条件下或某个时刻)

函数深入 1. 原型与原型链
  1. 函数的prototype属性
  • 每个函数都有一个prototype属性,它默认指向一个Object空对象(即称为:原型对象)

  • 原型对象中有一个属性constructor,它指向函数对象

在这里插入图片描述

  1. 给原型对象添加属性(一般都是方法)
  • 作用:函数的所有实例对象自动拥有原型中的属性(方法)
// 每个函数都有一个prototype属性, 它默认指向一个Object空对象(即称为: 原型对象)
console.log(Date.prototype, typeof Date.prototype)

function Fun () {}
console.log(Fun.prototype)  // 默认指向一个Object空对象(没有我们的属性)

// 原型对象中有一个属性constructor, 它指向函数对象
console.log(Date.prototype.constructor===Date) 	// true
console.log(Fun.prototype.constructor===Fun)	// true

//给原型对象添加属性(一般是方法) ===> 实例对象可以访问
Fun.prototype.test = function () {
    console.log('test()')
}
var fun = new Fun()
fun.test()

补充:构造函数与普通函数的区别:

  • 构造函数也是一个普通函数,创建方式和普通函数一样
  • 普通函数调用方式:直接调用person()
  • 构造函数调用方式:需要使用new关键字来调用 new person()
// 构造函数也是一个普通函数,创建方式和普通函数一样。
function Foo(){}
Foo();//普通函数调用方式
var f = new Foo();//构造函数调用方式
2. 显示原型属性和隐式原型属性
  • 所有函数都有一个特别的属性:prototype显式原型属性

  • 所有实例对象都有一个特别的属性:__proto__隐式原型属性

  • 显式原型属性与隐式原型属性的关系

    • 对象的隐式原型的值为其对应构造函数的显式原型的值 在这里插入图片描述
        //定义构造函数
      function Fn() {}
        // 1. 每个函数function都有一个prototype,即显式原型属性, 默认指向一个空的Object对象
        console.log(Fn.prototype)
        
        // 2. 每个实例对象都有一个__proto__,可称为隐式原型
        //创建实例对象
        var fn = new Fn()
        console.log(fn.__proto__)
        
        // 3. 对象的隐式原型的值为其对应构造函数的显式原型的值
        console.log(Fn.prototype===fn.__proto__) // true
        //给原型添加方法
        Fn.prototype.test = function () {
            console.log('test()')
        }
        //通过实例调用原型的方法
        fn.test()
    
    
  • 总结:

    • 函数的prototype属性:在定义函数时自动添加的,默认值是一个空Object对象
    • 对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值
    • 程序员能直接操作显式原型,但不能直接操作隐式原型(ES6之前)
  • 原型链 在这里插入图片描述

访问一个对象的属性时,先在自身属性中查找,找到返回;如果没有,再沿着__proto__这条链向上查找,找到返回;如果最终没找到,返回undefined

// 1. 函数的显示原型指向的对象默认是空Object实例对象(但Object不满足)
console.log(Fn.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false
console.log(Function.prototype instanceof Object) // true
// 2. 所有函数都是Function的实例(包含Function)
console.log(Function.__proto__===Function.prototype)
// 3. Object的原型对象是原型链尽头
console.log(Object.prototype.__proto__) // null

原型链-属性问题:

  1. 读取对象的属性值时:会自动到原型链中查找
  2. 设置对象的属性值时:不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值
  3. 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
function Fn() {}

Fn.prototype.a = 'xxx'
var fn1 = new Fn()
console.log(fn1.a)  // xxx

var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a, fn2.a) // xxx yyy
3. 执行上下文与执行上下文栈
  • 变量提升与函数提升

    • 变量提升:在变量定义语句之前,就可以访问到这个变量(undefined)

    • 函数提升:在函数定义语句之前,就执行该函数

    • 先有变量提升,再有函数提升

      函数提升必须使用声明的方式

      fn2() //可调用  函数提升
      fn3() //不能这样使用  变量提升
      // 声明方式
      function fn2() {
          console.log('fn2()')
      }
      
      // 变量方式
      var fn3 = function () {
          console.log('fn3()')
      }
      
  • 全局执行上下文

    • 在执行全局代码前将window确定为全局执行上下文
    • 对全局数据进行预处理
      • var定义的全局变量 ==> undefined,添加为window的属性
      • function声明的全局函数 ==> 赋值(fun),添加为window的方法
      • this ==> 赋值(window)
    • 开始执行全局代码
  1. 函数执行上下文
  • 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象(虚拟的,存在于栈中)
  • 对局部数据进行预处理
    • 形参变量 ==> 赋值(实参) ==> 添加为执行上下文的属性
    • arguments==>赋值(实参列表),添加为执行上下文的属性
    • var定义的局部变量==>undefined,添加为执行上下文的属性
    • function声明的函数 ==>赋值(fun),添加为执行上下文的方法
    • this==>赋值(调用函数的对象)
  • 开始执行函数体代码
  • 生命周期

    • 全局 : 准备执行全局代码前产生, 当页面刷新/关闭页面时死亡
    • 函数 : 调用函数时产生, 函数执行完时死亡
  • 包含哪些属性:

    • 全局 :
      • 用var定义的全局变量 ==> undefined
      • 使用function声明的函数 ===> function
      • this ===> window
    • 函数
      • 用var定义的局部变量 ==> undefined
      • 使用function声明的函数 ===> function
      • this ===> 调用函数的对象, 如果没有指定就是window
      • 形参变量 ===> 对应实参值
      • arguments ===> 实参列表的伪数组
  • 执行上下文创建和初始化的过程

    • 全局:
      • 在全局代码执行前最先创建一个全局执行上下文(window)
      • 收集一些全局变量, 并初始化
      • 将这些变量设置为window的属性
    • 函数:
      • 在调用函数时, 在执行函数体之前先创建一个函数执行上下文
      • 收集一些局部变量, 并初始化
      • 将这些变量设置为执行上下文的属性
4. 闭包
  • 如何产生闭包?

    当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包

    注意: 闭包存在于嵌套的内部函数中

  • 产生闭包的条件?

    1、函数嵌套 2、内部函数引用了外部函数的数据(变量/函数)

  • 闭包作用:

    • 使用函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期)
    1. 让函数外部可以操作(读写)到函数内部的数据(变量/函数)

    问题:

    1. 函数执行完后, 函数内部声明的局部变量是否还存在? 一般是不存在, 存在于闭中的变量才可能存在
    2. 在函数外部能直接访问函数内部的局部变量吗? 不能,但我们可以通过闭包让外部操作它
  • 写一个闭包程序

    function fn1() {
        var a = 2
        console.log(a)
    }
    console.log(a) // 报错,因为a没有定义,在函数外部无法操作函数内部的数据
    fn1()
    
    function fn2() {
      var a = 2;
      function fn3() {
        a++;
        console.log(a);
      }
      return fn3;
    }
    var f = fn2();
    f();// 在函数外部可以操作函数内部的数据
    f()
    
  • 闭包应用:

    • 模块化:封装一些数据以及操作数据的函数, 向外暴露一些行为

      function myModule() {
        //私有数据
        var msg = 'My Scorpios'
        //操作数据的函数
        function doSomething() {
          console.log('doSomething() '+msg.toUpperCase())
        }
        function doOtherthing () {
          console.log('doOtherthing() '+msg.toLowerCase())
        }
      
        //向外暴露对象(给外部使用的方法)
        return {
          doSomething: doSomething,
          doOtherthing: doOtherthing
        }
      }
      
      
      (function () {
        //私有数据
        var msg = 'My Scorpios'
        //操作数据的函数
        function doSomething() {
          console.log('doSomething() '+msg.toUpperCase())
        }
        function doOtherthing () {
          console.log('doOtherthing() '+msg.toLowerCase())
        }
      
        //向外暴露对象(给外部使用的方法)
        window.myModule2 = {
          doSomething: doSomething,
          doOtherthing: doOtherthing
        }
      })()
      
  • 缺点:

    • 变量占用内存的时间可能会过长
    • 可能导致内存泄露
    • 解决:及时释放f = null; //让内部函数对象成为垃圾对象
面向对象深入 1. 对象的创建模式
  • Object构造函数模式

    var obj = {};	// 先创建空Object对象,此时内部数据是不确定的
    obj.name = 'Tom'	
    obj.setName = function(name){this.name=name}
    

    问题:语句太多

  • 对象字面量模式

    var obj = {
      name : 'Tom',
      setName : function(name){this.name = name}
    }
    

    问题:如果创建多个对象,有重复代码

  • 工厂模式

    function createPerson(name, age) { //返回一个对象的函数===>工厂函数
        var obj = {
            name: name,
            age: age,
            setName: function (name) {
                this.name = name
            }
        }
        return obj
    }
    
    // 创建2个人
    var p1 = createPerson('Tom', 12)
    

    问题:对象没有一个具体的类型,都是Object类型

  • 构造函数模式

    function Person(name, age) {
      this.name = name;
      this.age = age;
      this.setName = function(name){this.name=name;};
    }
    new Person('tom', 12);
    

    问题:每个对象都有相同的数据,浪费内存

  • 构造函数+原型的组合模式

    function Person(name, age) {
      this.name = name;
      this.age = age;
    }
    Person.prototype.setName = function(name){this.name=name;};
    new Person('tom', 12);
    
2. 继承模式
  • 原型链继承 : 得到方法
    function Parent(){}
    Parent.prototype.test = function(){};
    
    function Child(){}
    Child.prototype = new Parent(); // 子类型的原型指向父类型实例
    Child.prototype.constructor = Child
    var child = new Child(); //有test()
    
  • 借用构造函数 : 得到属性
    function Parent(xxx){this.xxx = xxx}
    Parent.prototype.test = function(){};
    function Child(xxx,yyy){
        Parent.call(this, xxx);//借用构造函数   this.Parent(xxx)
    }
    var child = new Child('a', 'b');  //child.xxx为'a', 但child没有test()
    
  • 组合
    function Parent(xxx){this.xxx = xxx}
    Parent.prototype.test = function(){};
    function Child(xxx,yyy){
        Parent.call(this, xxx);//借用构造函数   this.Parent(xxx)
    }
    Child.prototype = new Parent(); //得到test()
    var child = new Child(); //child.xxx为'a', 也有test()
    

在这里插入图片描述

  • new一个对象背后做了些什么?
    • 创建一个空对象
    • 给对象设置__proto__,值为构造函数对象的prototype属性值 this.__proto__= Fn.prototype
    • 执行构造函数体(给对象添加属性/方法)
关注
打赏
1657848381
查看更多评论
立即登录/注册

微信扫码登录

0.0440s