为了账号安全,请及时绑定邮箱和手机立即绑定

JavaScript 基础知识

标签:
JavaScript

JS 基本数据类型

Undefined、Null、Boolean、String、Number

ES6 新增 Symbol,表示独一无二的值,凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突

Null 和 Undefined 的区别:

  • null:表示一个对象是“没有值”的值,即值为“空”;typeof 为 object

  • undefined:表示一个声明但没有初始化的变量;typeof 为 undefined

JS 的数据类型、及内存位置

栈:原始数据类型(Undefined、Null、Boolean、Number、String)

堆:引用数据类型(对象、数组、函数)

JS 内置对象

数据封装对象:Object、Array、Boolean、Number、String、Map、WeakMap、Set、WeakSet

其他对象:Function、Arguments、Math、Date、RegExp、Error

Object 是 JS 中所有对象的父对象

原型、原型链

每个对象都会在其内部初始化一个属性,就是 prototype (原型)

当我们访问一个对象的属性时, 如果这个对象内部不存在这个属性,那么他就会去 prototype 里找这个属性,这个prototype 又会有自己的 prototype , 于是就这样一直找下去,这样的一个链型结构就是原型链

let obj = Object.create(null)

这种方式创建的对象没有原型。使用的情景:

  • 你需要一个非常干净且高度可定制的对象当作数据字典的时候;

  • 想节省 hasOwnProperty 带来的一丢丢性能损失并且可以偷懒少些一点代码的时候

JS 创建对象的方式

工厂模式

function createPerson(name, age) {  var o = new Object();
  o.name = name;
  o.age = age;
  o.sayName = function () {
    alert(this.name);
  }  return 0;
}var person = createPerson('OreChou', 23);

所创建的对象的原型都为 Object 。这种方式无法解决对象识别问题,即使用 instance 和 typeof 的时候,其值为 Object。

构造函数模式

// 此处的函数名首字母为大写,约定构造函数的首字母为大写function Person(name, age) {  this.name = name;  this.age = age;  // 方法会在每个实例上重新创建一遍
  this.sayName = function() {
    alert(this.name);
  }  // 上面的代码与下面的等价
  // 相当于每次新建实例,都会创建一个函数,函数也是对象。所以有性能的开销
  this.sayAge = new Function("alert(this.age)");
}var person = new Person('OreChou', 23);
person.constructor === Person // trueperson instanceof Person // true

调用构造函数会经历以下步骤:

  • 以该函数为原型创建一个新对象

  • 将函数的 prototype 赋值给对象的 proto 属性

  • 将函数的作用域赋给新对象(即 this 指向了该新对象),执行函数中的代码

  • 若有 return(且不为基础类型)则返回 return 的内容,没有则返回新对象

缺点:

  • 每个方法都会在实例上重新创建一遍(解决:把这种方法改成全局的,或者使用原型)

构造函数 + 原型模式

function Person(name, age) {  this.name = name;  this.age = age;
}

Person.prototype = {  // 这里指定了构造函数为 Person
  // 若不指定,则 Person 的原型为 Object
  constructor: Person,
  sayName: function() {
    alert(this.name);
  }
}

Person.prototype.sayAge = function() {
  alert(this.age);
}var person = new Person('OreChou', 23);

Person.prototype.isPrototypeOf(person) // true

每一个函数都有一个 prototype 属性,属性为一个指针,指向一个对象。该对象可以包含该特定类型的所有实例共享的属性与方法。

构造函数的 prototype 属性,实例的 [[prototype]] 属性(Chrome、Safari、Firefox中每个实例对象上的属性 proto ),都指向函数的原型对象。

使用 Class

class Person {  // 等价于 Person 的构造函数
  // 除 constructor 外没有其他方法的保留名
    constructor(name, age) {    this.name = name;    this.age = age;
  }  // 等价于 Person.prototype.sayName
  // 类中所有方法都是不可枚举的
  sayName() {        console.log(this.name);
  }
}// 上面和下面两种方法等价let Person = (function() {  'use strict';  const Person = function(name, age) {    if (typeof new.target === 'undefined') {      throw new Error('必须通过关键字 new 调用函数');
    }    this.name = name;    this.age = age;
  }  Object.defineProperty(Person.prototype, 'sayName', {    value: function() {      if (typeof new.target !== 'undefined') {        throw new Error('不可以使用关键字 new 调用该方法');
      }            console.log(this.name);
    },    // 当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false。
    enumerable: false,    // 当且仅当该属性的 writable 为 true 时,value 才能被赋值运算符改变。默认为 false。
    writable: true,    // 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。
    configurable: true
  })  return Person;
})

使用类的注意事项:

  • 类声明与 let 类似,不能被提升

  • 类中的所有代码自动运行在严格模式下

  • 类中所有方法都是不可枚举的

  • 类中有一个名为 constructor 的方法,且只能使用 new 调用,否则报错

  • 类中其他的方法不能使用 new 调用,否则报错

JS 实现继承的方式

假设有如下的一个 Animal 类

function Animal() {  this.species = '动物'}

构造函数继承

function Person(name, age) {  // 使用call或apply方法,将父对象的构造函数绑定在子对象上
  Animal.apply(this, arguments);  this.name = name;  this.age = age;
}

原型继承

function Person(name, age) {  this.name = name;  this.age = age;
}// (1)// 将 Person 的原型对象指向 Animal 的实例 (这种方式因为新增了 Animal 的一个实例,所以消耗了内存)// 此时的 Person.prototype.constructor 指向了 PersonPerson.prototype = new Animal();// 这样导致了继承链混乱,所以将 constructor 改回 PersonPerson.prototype.constructor = Person;// (2)// 这种方式不会新增内存,但是对 Person 原型的修改会反应到 Aniaml 的原型上Person.prototype = Animal.prototype// (3)// 利用空对象作为中介。F 是空对象,几乎不占据内存,且修改 Person 的原型,不会反应到 Animal 的原型上var nullObj = function() {};
F.prototype = Animal.prototype;
Person.prototype = new F();
Person.prototype.constructor = Person;

拷贝继承

实现一个拷贝函数,将父对象的所有属性方法拷贝到子对象

// 浅拷贝的实现function shallowCopy(p) {  var c = {};  for (var i in p) {    // js 的对象是一个指针,指向了该对象在内存中的地址
    // 所以这里如果属性是一个对象的话,其实只拷贝了该对象的地址
    // 那么拷贝后的对象对该属性的修改,会影响到原对象
    c[i] = p[i];
  }  return c;
}// 深拷贝的一个简单实现function deepCopy(p) {  // 确定 p 为对象还是数组
  var c = Array.isArray(p) ? [] : {};  if (p && typeof p === 'object') {    for (var i in p) {      // 如果属性是对象,则递归拷贝
      if (p[i] && typeof p[i] === 'object') {
          c[i] = deepCopy(p[i]);
      } else {
        c[i] = p[i];
      }
    }
  }  return c;
}



作者:OreChou的小号
链接:https://www.jianshu.com/p/27da89f64abe


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消