重学javascript

一 javascript的历史

先从这门语言的历史谈起是有必要的。

  • 在1995 年 Netscape 一位名为 Brendan Eich 的工程师创造了 JavaScript
  • 随后在 1996 年初,JavaScript 首先被应用于 Netscape 2 浏览器上。最初的 JavaScript 名为 LiveScript,后来,因为 Sun Microsystem 的 Java 语言兴起,被广泛使用,Netscape
    出于宣传和推广的考虑,将它的名字从最初的 LiveScript 更改为 JavaScript
  • 几个月后,Microsoft 随 IE 3 发布推出了一个与之基本兼容的语言 JScript。
  • 又过了几个月,Netscape 将 JavaScript 提交至 Ecma International(一个欧洲标准化组织), ECMAScript 标准第一版便在 1997 年诞生了
  • 随后在 1999 年以 ECMAScript 第三版的形式进行了更新,从那之后这个标准没有发生过大的改动。
  • 由于委员会在语言特性的讨论上发生分歧,ECMAScript 第四版尚未推出便被废除,
  • 但随后于 2009 年 12 月发布的 ECMAScript 第五版引入了第四版草案加入的许多特性。
  • 第六版标准已经于 2015 年 6 月发布。

二 类型

  • Numer
  • String
  • Boolean
  • undefined
  • null (前5个是基本类型)
  • Object
    Function
    Array
    Date
    RegExp
  • Symbol (ES2015 新增)
1. 数字

JavaScript 采用“遵循 IEEE 754 标准的双精度 64 位格式”
JavaScript 不区分整数值和浮点数值,所有数字在 JavaScript 中均用浮点数值表示,所以在进行数字运算的时候要特别注意

特殊的例子 0.1 + 0.2 = 0.30000000000000004
原因:EcmaScrpt规范定义Number的类型遵循了IEEE754-2008中的64位浮点数规则定义的小数后的有效位数至多为52位导致计算出现精度丢失问题!在十进制转换为二进制的过程中,会产生精度的损失。二进制浮点数进行对阶运算时,也会产生精度的损失。

常用方法
  • parstInt
  • Math.sin
  • isNaN
  • isFinite
2. 字符串
常用方法
  • charAt
  • replace
  • toUpperCase
3. null undefined

null 空值
undefined 是一个“undefined(未定义)”类型的对象,表示一个未初始化的值,也就是还没有被分配的值 (一个未被赋值的变量)

4. Boolean
  • false、0、空字符串("")、NaN、null 和 undefined 被转换为 false
  • 所有其他值被转换为 true

三 变量

  • let 申明一个块级作用域
  • const 声明不可变常量
  • var 声明变量 没有块级作用域
1.作用域

作用域指的是变量所作用的范围,有两种作用域:

  • 全局作用域
  • 函数作用域 :定义在函数中的参数和变量在函数外部是不可见的
  • 块级作用域:任何一对花括号{}中的语句集都属于一个块,在这之中定义的所有变量在代码块外都是不可见的,我们称之为块级作用域。
function foo() {
    if(true) {
        var temp = 5;
         console.log(temp);
    }
    
    console.log(temp);
}

function bar({
    if(true) {
        let temp = 5;
        console.log(temp);
    }
    
    console.log(temp);
}

foo(); // 5 和 5
bar(); // 5 和 "ReferenceError: temp is not defined
2.变量提升

变量提升:所有通过 var 声明的变量会提升到当前作用域的最前面

function foo() {
    console.log(temp); 
}

function bar() {
    console.log(temp);  
    var temp;
}

foo(); // ReferenceError: temp is not defined
bar(); // undefined
3.暂时性死区

暂时性死区:使用 let 或 const 声明的变量,在声明没有到达之前,访问该变量都会导致报错

4.禁止重复声明

var 会覆盖重复声明,不会报错
let const 会报错重复声明

四 运算符

+、-、*、/ 和 % ++ 和 –

五 控制结构

  • if 和 else
  • while 循环和 do-while
while (true) {
  // 一个无限循环!
}

var input;
do {
  input = get_input();
} while (inputIsNotValid(input))
  • for
for (var i = 0; i < 5; i++) {
  // 将会执行五次
}
  • for in
for (let property in object) {
  // do something with object property
}
  • for of
for (let value of array) {
  // do something with value
}
  • && ||
  • 三元操作符 var allowed = (age > 18) ? "yes" : "no";
  • switch
switch(action) {
    case 'draw':
        drawIt();
        break;
    case 'eat':
        eatIt();
        break;
    default:
        doNothing();
}

六 对象

创建对象

var obj = new Object(); // 1.创建一个包装对象
var obj = {};  // 2.对象字面量
var a = {a: 1}; 
// a ---> Object.prototype ---> null
var b = Object.create(a);  // 3.使用 Object.create 创建的对象
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (继承而来)

// 4.使用class
class Polygon {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

方法: hasOwnProperty Object.keys() 不会便利原型链上面的方法

1. 构造函数
var Person = function(name) {
	this.name = name
}
function Person(name) {
	this.name = name;
}
  • 函数体内this代表所要生成的对象实例。
  • 生成对象,用new 调用构造函数 new Person(“ff”)
2. new

new 原理:执行构造函数,返回一个实例对象:
(1)创建一个空对象,作为返回的空对象
(2)将空对象的原型指向构造函数的prototype属性
(3)将空对象赋值给构造函数内部的this关键字
(4)开始执行构造函数内部代码
(5)注意问题 如果构造函数内部有return语句,而且return后面跟着一个对象,如果构造函数内部有return语句,而且return后面跟着一个对象,new命令会返回return语句指定的对象;否则,就会不管return语句,返回this对象。

var Vehicle = function () {
  this.price = 1000;
  return 1000;
};

(new Vehicle()) === 1000
// false
var Vehicle = function (){
  this.price = 1000;
  return { price: 2000 };
};

(new Vehicle()).price
// 2000
  • 如果对普通函数(内部没有this关键字的函数)使用new命令,则会返回一个空对象。
function getMessage() {
  return 'this is a message';
}

var msg = new getMessage();

msg // {}
typeof msg // "object"
2.1 自己实现一个new
function objectFactory() {
	const obj = new Object();
	const Constructor = [].shift.call(arguments);
	Constructor.__proto__ = Constructor.prototype;
	// Object.setPrototypeOf(obj,Constructor.prototype) 
	// let obj = Object.create(Constructor.prototype)
	const rest = Constructor.apply(obj,arguments);
	return type rest === 'object' ? rest : obj;
	// return res instanceof Object ? res : obj;
}
3.原型

原型:原型是个对象,通过原型可以实现对象的属性继承。在构造函数创建时,系统会给这个构造函数关联一个对象,这个对象就是原型。

3.1 原型链

每个实例对象( object )都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( proto ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个中的最后一个环节。
在这里插入图片描述

3.2 prototype

每个函数都有一个prototype属性

function Person() {

}
// 虽然写在注释里,但是你要注意:
// prototype是函数才会有的属性
Person.prototype.name = 'Kevin';
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // Kevin
console.log(person2.name) // Kevin

函数的protptype属性指向一个对象,这个对象是调用构造函数而创建的实例的原型,也就是person1和person2的原型。
在这里插入图片描述

3.2 proto

每个对象都有一个__proto__属性,指向改对象的原型

function Person() {

}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true

在这里插入图片描述

3.3 constructor

每个原型都有一个 constructor 属性指向关联的构造函数

function Person() {

}
console.log(Person === Person.prototype.constructor); // true

var person = new Person();
console.log(person.constructor === Person); // true
// person.constructor === Person.prototype.constructor

在这里插入图片描述

function Person {}
var person = new Person();
console.log(person.__proto__ == Person.prototype) // true
console.log(Person.prototype.constructor == Person) // true
// 顺便学习一个ES5的方法,可以获得对象的原型
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
3.4 原型的原型

其实原型对象就是通过 Object 构造函数生成的,结合之前所讲,实例的 proto 指向构造函数的 prototype
在这里插入图片描述

4. 继承
5. 设计模式
5.1 工厂模式
function creatPerson() {
	var o = new Object();
    o.name = name;
    o.getName = function () {
        console.log(this.name);
    };
    return o;
}
var person = createPerson('zw');

缺点: 对象无法识别,因为所以对象的实例都指向一个原型

5.2 构造函数模式
function Person(name) {
	this.name = name;
	this.getName = function () {
		console.log(this.name)
	}
}
var person = new Person('zw')

优点: 实例可以识别为一个特点的类型
缺点: 每次创建实例时,每个方法都要被创建一次

5.3 原型模式
function Person(name) {
}
Person.prototype.name = 'zw';
Person.prototype.getName = function () {
		console.log(this.name)
}

优点:方法不会被重新创建
缺点:所有的属性和方法都共享 不难初始化参数
原型模式优化

function Person(name){
}
Person.prototype = {
	name: 'zw',
	getName: function() {
		console.log(this.name);
	}
}

优点:封装性好了一点
缺点:重写了原型,丢失了constructor属性
原型模式优化

function Person(name) {

}

Person.prototype = {
    constructor: Person,
    name: 'kevin',
    getName: function () {
        console.log(this.name);
    }
};

优点:实例可以通过constructor属性找到所属构造函数
缺点:原型模式该有的缺点还是有

5.4 组合模式
function Person(name){
	this.name = name;
}
Person.prototype = {
	constructor: Person,
	getName: function() {
		console.log(this.name);
	}
}

优点:该共享的共享,该私有的私有,使用最广泛的方式
缺点:有的人就是希望全部都写在一起,即更好的封装性

5.5 动态原型模式
function Person(name) {
    this.name = name;
    if (typeof this.getName != "function") {
        Person.prototype.getName = function () {
            console.log(this.name);
        }
    }
}

function Person(name) {
    this.name = name;
    if (typeof this.getName != "function") {
        Person.prototype = {
            constructor: Person,
            getName: function () {
                console.log(this.name);
            }
        }
        return new Person(name);
    }
}
5.6 寄生构造函数模式
function Person(name) {
    var o = new Object();
    o.name = name;
    o.getName = function () {
        console.log(this.name);
    };
    return o;

}
var person1 = new Person('kevin');

所谓的寄生构造函数模式就是比工厂模式在创建对象的时候,多使用了一个new,实际上两者的结果是一样的。

5.7 稳妥构造函数模式
function person(name){
    var o = new Object();
    o.sayName = function(){
        console.log(name);
    };
    return o;
}

var person1 = person('kevin');

所谓稳妥对象,指的是没有公共属性,而且其方法也不引用 this 的对象。

与寄生构造函数模式有两点不同:

新创建的实例方法不引用 this
不使用 new 操作符调用构造函数
稳妥对象最适合在一些安全的环境中。

稳妥构造函数模式也跟工厂模式一样,无法识别对象所属类型。

参考文档
  1. https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript
  2. https://wangdoc.com/javascript/oop/new.html
  3. https://github.com/mqyqingfeng/Blog/labels/%E6%B7%B1%E5%85%A5%E7%B3%BB%E5%88%97
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值