前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS学习笔记

JS学习笔记

作者头像
小丞同学
发布2021-08-16 16:03:18
3840
发布2021-08-16 16:03:18
举报
文章被收录于专栏:小丞前端库

预编译

  1. 创建AO对象
  2. 找函数形参和变量声明,值给undefined
  3. 实参形参统一
  4. 在函数体里面找函数声明,值赋予函数体
代码语言:javascript
复制
function fn(a){
   console.log(a); //在AO里找值--->输出 function a() {}
   var a = 123; //预编译将 var a,提升上去了,执行 a = 123;修改AO中a的值
   console.log(a); //输出 123
   function a() {} //预编译读过,不再读
   console.log(a); //输出 123
   var b = function() {} //函数表达式,将AO中b的值改为function () {}
   console.log(b); //输出funtion () {}
   function d() {}
}
fn(1);
代码语言:javascript
复制
第一步:AO{ }
第二步:
AO{
a : undefined,
b : undefined
}
第三步:
AO{
a : 1,
b : undefined
}
第四步:
AO{
a : function a() {},
b : undefined,
d : function d() {}
}

立即执行函数

此类函数没有声明,在一次执行过后即释放,可以用来做初始化

代码语言:javascript
复制
var mrDeng = (function(){
    var Deng = {
        name : "MrDeng",
        age : 40,
        sex : "male",
        health : 100,
        smoke : function () {
            console.log('I am smoking! cool!!!');
            this.health --;
        },
        drink : function () {
            console.log('I am drink');
            this.health ++;
        }
    }
    return Deng;
}())

这样可以实现初始化的效果


闭包

内部函数被返回到外部,函数本身保留了父函数的AO,即使父元素执行完了,取消对AO的引用,但依旧被子函数保留下来了,就形成了闭包。

闭包会导致原有作用域链不释放,造成内存泄漏。

作用

1. 实现公有变量(累加器)

因为子函数保留有父函数的AO,并在此基础上搭建自己的AO,所以父函数的AO会被作为一个公有变量被使用,即使函数执行完毕,也只会销毁自己创建的AO对象。

2. 实现封装,属性私有化

简单理解就是函数结束会销毁父函数的执行上下文,但是应用闭包可以使父函数的执行上下文被保留下来,给父函数下的其他函数使用,这样就实现了属性的私有化

3. 模块化开发

4. 防止污染全局变量

代码语言:javascript
复制
var name = 'abc';//全局变量
var init = (function() {
    var name = 'ljc';
    function callName() {
        console.log(name);
    }
    return function () {
        callName();
    }//返回一个函数形成闭包,留有父函数的AO{name: 'ljc'}
}())
init();//ljc

5. 缓存(存储结构)

防范

闭包会导致多个执行函数共用一个公有变量,应当尽量避免

利用闭包解决for循环绑定事件的问题
代码语言:javascript
复制
function test(){
   var liCollection = document.getElementByTagName('li');
   for(var i = 0; i < liCollection.length; i++){
      (function (j){
         liCollection[j].onclick = function(){ //把函数绑定到了每个li元素(外部)
            console.log(i);
         }
      }(i))
   }
}
test();

包装类

原始值没有属性和方法,强行添加属性或者访问属性的话,系统就会新建一个包装类,然后在包装类上进行操作,操作完成后再销毁。

代码语言:javascript
复制
var num = 4;//这里的num是原始值没有属性和方法

num.len = 3;//强行添加属性
//new Number(4).len = 3;执行完立刻销毁 delete
//再次调用的时候再次生成Number()
//new Number(4).len
consloe.log(num.len);

数组在改小length的时候会被截短


原型

原型是function对象下的属性,它定义了构造函数的共同祖先,也就是一个父子级的关系,子对象会继承父对象的方法和属性

  1. prototype是函数下的属性,对象想要查看原型使用隐式属性__Proto__
  2. constructor指向构造函数
  3. 自己身上有属性,原型上也有属性,取近的,用自己的

通过给原型添加属性,可以让所有的实例化对象共享属性和方法

代码语言:javascript
复制
Car.prototype = {
	height : 1400,
	lang : 4900,
	carName : 'BMW'
}
function Car() {
}
var car = new Car();

原型链

每个实例对象下都有__proto__属性,通过属性__proto__指向构造函数的原型对象,当到达末端时,返回null,这样一层一层向顶端查找,就形成了原型链

prototype是函数特有的,__proto__是对象有的,js中万物皆对象

prototype和——proto——区别与作用

prototype把共有属性预先定义好,给之后对象使用

prototype的存在实现了继承,节省内存空间

__proto__是对象的,prototype是函数的,因为函数也是对象,所以函数也有__proto__

__proto__的作用是就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会沿着它的**__proto__**属性所指向的那个对象(父对象)里找,也就是原型链

prototype的作用是就是让该函数所实例化的对象们都可以找到公用的属性和方法

__proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

constructor构造函数

constructor属性存在于__proto__prototype,它指向构造函数本身

一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,我们可以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了。此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。

问题 修改了函数的原型对象,constructor的指向是谁

代码语言:javascript
复制
 function Star(uname, age) {
     this.uname = uname;
     this.age = age;
 }
 // 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
 Star.prototype = {
 // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
   constructor: Star, // 手动设置指回原来的构造函数
   sing: function() {
     console.log('我会唱歌');
   },
   movie: function() {
     console.log('我会演电影');
   }
}
var zxy = new Star('张学友', 19);
console.log(zxy)

在修改函数原型时,因为Star.prototype就是一个对象,所以constructor指向构造这个对象的原型,也就是object

call/apply

通过call``apply可以改变this的指向,借用别人的函数完成自己的功能

区别:call传多个参数 apply传一个参数数组

代码语言:javascript
复制
function Person(name,age,sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
function Student(name,age,sex,tel,grade) {
    //var this = {name: "lin", age: "19", sex: "male", tel: 123, grade: 78}
    Person.call(this,name,age,sex);//通过call改变this的指向这个函数
    //Person.apply(this,[name,age,sex])
    this.tel = tel;
    this.grade = grade;
}
var student = new Student('lin','19','male',123,78);
new()
  1. 创建一个空对象
  2. 构造函数的this,继承函数原型
  3. 让this指向构造函数的对象实例,执行构造函数内容为新对象添加属性和方法
  4. 返回this
代码语言:javascript
复制
var obj = {}//创建空对象
obj.__proto__ = Person.prototype;//继承作用域
Person.call(obj,)//改变this指向
//这三步是隐式的
var person = new Person();//new操作

继承

原型链方法

继承了过多没用的属性

通过使用new关键字来实现继承父元素属性和方法,再通过prototype属性来改变函数原型,从而实现一条完整的原型链,从而实现子函数可以继承父函数的属性和方法

代码语言:javascript
复制
function Father() {
    this.name = 'hhh';
}
var father = new Father();
Son.prototype = father;
function Son() {
}
var son = new Son();//son下继承了father的name
借用构造函数

不能继承构造函数的原型

代码语言:javascript
复制
 // 1. 父构造函数
 function Father(uname, age) {
   // this 指向父构造函数的对象实例
   this.uname = uname;
   this.age = age;
 }
  // 2 .子构造函数 
function Son(uname, age, score) {
  // this 指向子构造函数的对象实例
 // 3.使用call方式实现子继承父的属性
  Father.call(this, uname, age);
  this.score = score;
}
var son = new Son('lin', 19, 100);
console.log(son);
共享原型

Son.prototype = Father.prototype,不能改动自己的原型

代码语言:javascript
复制
Father.prototype.lastName = 'lin';
function Father() {
    this.name = 'hhh';
}
function Son() {
}
Son.prototype = Father.prototype;//son和father共用原型
var father = new Father();
var son = new Son();
圣杯模式

在共享原型的基础上加多一个构造函数F做中间层,让F和Father共有原型,也就是把Father的原型赋值给F一份,在F和son之间操作,这样就可以隔开son和father但又不影响继承

代码语言:javascript
复制
function inherit(Target,Origin) {
    function F() {}
    F.prototype = Origin.prototype;//把父元素的原型给F
    Target.prototype = new F();//通过new的方法把F的原型返回给目标
}
Father.prototype.lastName = 'lin';
function Father() {}
function Son() {}
inherit(Son.Father);
var son = new Son();
var father = new Father();

枚举

遍历对象

var k in obj,k是obj中对象属性,obj是我们要遍历的对象

代码语言:javascript
复制
var obj = {
	a : '1',
	b : '2',
	c : '3'
}
var obj1 = {}
for(var k in obj) {
	if(obj.hasOwnProperty(k)){
                console.log(obj[k]);
            }
}

hasOwnProperty这个方法会判断这个属性是不是你自己的,是返回true

instanceof方法,A instanceof B意思是A对象是不是B构造函数构造出来的,看A的原型链上有没有B的原型

判断是数组还是对象

  1. constructor// array ||Object
  2. instanceof// true || false
  3. toString // ‘[object Array]’ || [‘object Object’]

this指向

谁调用指向谁,没有就是window

使用new关键字实例化对象时,this指向新创建的对象

  1. 函数预编译过程this指向window
  2. 全局作用域里this指向window
  3. call/apply改变this指向
  4. obj.fun();fun()里的this指向obj

**argument.callee**可以返回自己的引用,在哪个函数里面就指代哪个函数

代码语言:javascript
复制
//callee用法
var n = (function(num){
    if(num == 1){
        return 1;
    }else {
        return num * arguments.callee(num - 1);
        /*通过callee返回了函数本身,使得再次被调用*/
    }
}(3))
console.log(n);

克隆

浅克隆

浅克隆无法copy数组和对象

代码语言:javascript
复制
var obj = {
    name : "abs",
    age : '18',
    sex : 'male'
}
var obj1 = {}
function clone(Origin,target) {
    target = target || {};//防止用户不输入target
    for(var k in Origin){
        target[k] = Origin[k];
    }
}
clone(obj,obj1);
深克隆

先判断它是什么,原始值,数组还是对象,分别处理

  1. 遍历对象
  2. 是原始值直接copy
  3. 不是原始值判断是数组还是对象
  4. 是数组建空数组
  5. 是对象建空对象
  6. 建立了之后再遍历一遍原始对象或数组里是啥
  7. 递归
代码语言:javascript
复制
var obj = {
    name : 'lin',
    age : '18',
    sex : 'male',
    card : [1,2,3,4],
    wife : {
        name : 'bcsds',
        son : {
            name : 'aaa'
        },
        age : '23'
    }
}
var obj1 = {}
//原始值和对象数组typeof返回值有区别
function deepClone(origin,target) {
    target = target || {};
    for(var k in origin) {
        if(origin.hasOwnProperty(k)){
            if(typeof(origin[k]) == 'object') {
                if(Object.prototype.toString.call(origin[k]) == '[object Array]') {
                    target[k] = [];
                }else {
                    target[k] = {};
                }
                deepClone(origin[k],target[k]);
            }else {
                target[k] = origin[k];
            }
        }
    }
}
deepClone(obj,obj1);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/03/13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 预编译
  • 立即执行函数
  • 闭包
    • 作用
      • 防范
        • 利用闭包解决for循环绑定事件的问题
        • 包装类
        • 原型
        • 原型链
          • prototype和——proto——区别与作用
            • constructor构造函数
              • call/apply
                • new()
                • 继承
                  • 原型链方法
                    • 借用构造函数
                      • 共享原型
                        • 圣杯模式
                        • 枚举
                        • this指向
                        • 克隆
                          • 浅克隆
                            • 深克隆
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档