JavaScript基础笔记

本文详述JavaScript的基础知识,包括变量、数据类型、对象、数组、函数、作用域等核心概念,以及面向对象编程和JSON格式的应用。深入探讨了JavaScript的变量命名规范、对象创建方式、数组操作、正则表达式、函数表达式和闭包等高级特性,为读者提供全面的JS学习指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JavaScript简介

JavaScript已经成为一门功能全面的编程语言,能够处理复杂的计算和交互,拥有了闭包,匿名函数,甚至元编程等特性。

面向对象编程 —— Object Oriented Programming,简称 OOP ,是一种编程开发思想。
它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。

js是什么?

是一门解释性的语言
是一门脚本语言
是一门弱类型语言
是一门基于对象的语言
是一门动态类型的语言:
1、代码(变量)只有执行到这个位置的时候,才知道这个变量中存储的是什么。
2、对象没有什么,只有点了,通过点语法,那么就可以为对象添加属性或方法。

js三部分:

  • ECMAScript标准------js的基本语法
  • DOM------Document object Model 文档对象模型
  • BOM------Brower object Model 浏览器对象模型

js可以做的事:

  1. 网页特效;
  2. 服务端开发(Node.js);
  3. 命令行工具(Node.js);
  4. 桌面程序(Electron);
  5. App(Cordova);
  6. 控制硬件-物联网(Ruff);
  7. 游戏开发(cocosd-js);

规范

script标签一般是放在body的标签的最后,有时候会在head标签中。
变量名命名规范:一般都是小写;如果多个单词,第一个单词的首字母是小写的,后面的所有的单词的首字母都是大写的,这种命名方式称为:驼峰命名法。
项目里必须要有 //单行注释; /多行注释/
严格模式:在顶部添加"use strict" 。
最好把用完后不用的对象赋值为null,或者delete此对象。
函数内默认里面有一个name属性,值为函数名,只读。因而最好变量中不要使用name来命名属性,否则会出现未知错误。
函数中有一个caller属性,显示当前函数调用者。

了解

|-虽然语句结尾的分号不是必需的,但建议任何时候都不要省略它。
|-删除多余的空格来压缩ECMAScript。
|-arguments对象可以与命名参数一起使用,但与之一起使用,函数要么不写形参,若写形参就必须传入相同个数的实参,反之未被传入的形参等于undefined。

变量

声明变量:(区分大小写)

var 变量名;

js中的原始数据类型:

number,string,boolean,null,undefined,object。
两个特殊数值:①Infinity ②NaN
变量声明了,没有赋值,结果是undefined;或者函数没有明确返回值,但是接收了也为undefined。

获取变量的数据类型:

	typeof 变量名

Number类型

在js中表示进制:

​ 1.八进制:用0表示,后面接的时进制后的数字

var num = 012;	// 输出为10

​ 2.十六进制:用0x表示

var num = 0x1a; // 输出为26

isFinite()函数

判断参数是否位于最小和最大数值之间时会返回true。

isNaN()函数

接收一个参数,判断参数是否可以转换为数值。

·转数字:

parseInt(numString, [进制]);
parseFloat(numString); //只解析10进制值

·转String:

String(value);
toString([进制]);	// 不能对null,undefined操作

Object类型

Object的每个实例都具有下列属性和方法:

  • constructor:保存着用于创建当前对象的函数。
  • hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中是否存在。
  • isPrototypeOf(object):用于检查传入的对象是否是当前对象的原型。
  • propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。
  • toLocaleString():返回对象的字符串表示。
  • toString():返回对象的字符串表示。
  • valueOf():返回对象的字符串、数值或布尔值表示。

操作符

关系运算符:> < >= <= ==(不严格) ===(严格) != !==

三元运算符:

​ 表达式1 ? 表达式2 : 表达式3 //true执行表达式2,false执行表达式3

一元运算符:

var num = 10;
var sum = num ++ +10;	//20,先参与运算后再加一
var sum = ++num + 10;	//21,先加一再参与运算

运算

**分支结构:**if语句,if-else语句,if - else if - else if…语句,switch case语句,三元表达式。
**循环结构:**while循环,do while循环,for循环,for-in循环。
**调试:**浏览器F12,单击Sources,双击文件,设置断点;Watch设置自己想看的值;执行出现的蓝色框代表跳到那,但没有执行。
·变量定义:
语法:var 数组名 = new Array();或者var 数组名 = new Array[];
!!!注意:()或者[]内填一个数字为数字长度,多个数字则为元素。

函数(重要)

**函数注意问题:**要遵循驼峰命名法;一个函数只能完成一个功能。
**实参与形参:**实参是调用函数时传入的数或变量;形参是函数定义时定义在()内的参数。

function f1(x,y) {	// x,y为形参
    return x + y;
}
var result = f1(10,20);	//10,20为实参
console.log(result);

arguments对象(伪数组):

​ arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数的条目,第一个条目的索引从0开始。
arguments对象不是一个 Array 。它类似于Array,但除了length属性和索引元素之外没有任何Array属性,但可以转换为真的Array。

function f1() {
    console.log(arguments.length);	// 返回5
}
f1(10,20,30,40,50);
// 转为数组
function test(){
    var args = Array.prototype.slice.call(arguments);
    console.log(Object.prototype.toString.call(args));
}
test(1,2,3);
// 输出[object Array]

变量、作用域和内存问题

基本类型值:简单的数据段。
引用类型值:可能由多个值构成的对象。

复制及存储

在这里插入图片描述

检查类型

被检查对象或值 instanceof 鉴定对象或值;

作用域(执行环境)

**全局变量:**声明的变量是使用var声明的变量。
**局部变量:**在函数内部声明的变量。
**隐式全局变量:**声明的变量没有var,包括在函数声明的,外部也可以使用。
**全局作用域:**全局变量的作用范围。
**局部作用域:**隐式变量的作用范围(函数内);
!!!用var声明的变量不可删除,隐式全局变量可以被删除(delete num;)。

作用域链

|-环境与环境的关系。
|-是保证对执行环境有权访问的所有变量和函数的有序访问。
|-搜索由内向外,先当前环境,再父环境。

没有块级作用域

比如在if定义了属性或for初始化变量的表达式所定义的变量,在}结束后会添加到全局变量中,也可以访问。

附加

JSON格式的数据

  • 一般都是成对的,是键值对。
  • 一般JSON格式的数据无论键还是值都是用双引号括起来的。
    例:
var json = {
    "name" : "小明",
    "age" : "10"
};
// 访问
json["name"];	或者	json.age;(遍历对象中确实有这个属性才可这样写,访问无影响)
// 遍历
for(var key in json) {	// key存的时json对象的所有属性名
    console.log(json[key]);
}

简单类型和复杂类型

|-原始数据类型:number,string,boolean,undefined,null,object。
|-基本类型(简单类型),值类型:number,string,boolean。
|-复习类型(引用):object。
|-空类型:undefined,null。

  • 值类型栈中存储
  • 引用类型:对象在堆中存储,地址在栈中存储。
  • 值类型之间传递,传递的是值。
  • 引用类型之间传递,传递的时地址(引用)。
  • 每当读取一个基本类型值的时候,后台就会创建一个队友的基本包装类型的对象;使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。
    必须理解:
function f1(x) {
    x = 100;
}
var num = 10;
f1(num);
console.log(num);	// 输出为10,因为x与num无关
var obj={
    name : "小明"
};
function f2(obj2) {
    obj2.name = "小红";
}
console.log(obj.name);	// 小明
f2(obj);
console.log(obj.name);	// 小红;以为传进去的是obj的地址。

引用类型

是一种数据结构,用于将数据和功能组织在一起,也常被称为类。

Object类型

	var person = new Object();
	person.name = "Nicholas";
	person.age = 29;

添加属性:
对象.名字 = 值; // 调用格式:对象.名字;
添加方法:
对象.名字 = 函数; //调用格式:对象.名字();

对象字面量的方式创建对象

缺点:只能固定值,不能传变量。一次性的对象。

var obj = {
    name : "小明",
    age : "18",
    sayHi : function() {
        console.log("我叫" + this.name);
    }
}
obj.sayHi();

另一种设置和获取属性方法(不推荐)

设置:对象名[“属性名”] = 值;
获取:对象名[“属性名”];

Array类型

var colors = new Array();
访问:colors[索引]
赋值:colors[索引] = 值或对象;
!数组的length属性不止是只读,也可从数组的末尾移除项或向数组中添加新项。
colors.length = 长度;  //会删除长度后的项

常用属性和方法

.length // 获取数组长度
Array.isArray(obj) //确定传递的值是否是一个Array。
Array.from(arrayLike[, mapFn[, thisArg]]) // 从一个类似数组或可迭代对象中创建一个新的数组实例。arrayLike可以使arguments。
var new_array = old_array.concat(value1[, value2[, …[, valueN]]]) // 用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
every(callback[, thisArg]) // 测试数组的所有元素是否都通过了指定函数的测试。callback函数。callback 被调用时传入三个参数:元素值,元素的索引,原数组。新
filter(callback[, thisArg]) // 创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
push(element1,…, elementN) // 将一个或多个元素添加到数组的末尾,并返回新数组的长度。
pop() // 从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。
shift() // 从数组中删除第一个元素,并返回该元素的值。
unshift(element1, …, elementN) // 将一个或多个元素添加到数组的开头,并返回新数组的长度。
forEach(callback(currentValue, index, array),this) // 对数组的每个元素执行一次提供的函数。新

**详细看:**https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array

检测数组Array.isArray();

内置对象

js学习中三种对象:
|-内置对象—js系统自带的对象;Math,Date,String,Array,Object
|-自定义对象—自己定义的构造函数创建的对象
|-浏览器对象—BOM

Date对象

​ 创建Date实例用来处理日期和时间。基于1970年1月1日。

构造函数:

new Date();
new Date(value);
new Date(dateString);
new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);

常用方法:
对象.getFullYear() // 返回年份
对象.getMonth() // 返回月份,但需加一
对象.getDate() // 返回日期
对象.getHours() // 返回小时
对象.getMinutes() // 返回分钟
对象.getSeconds() // 返回秒
对象.getDay() // 返回星期,星期日为0
对象.toLocaleDateString() // 返回该日期对象日期部分的字符串
对象.toDateString() // 返回一个美式日期对象日期部分的字符串
详细看https://developer.mozilla.org/zhCN/docs/Web/JavaScript/Reference/Global_Objects/Date

RegExp类型(正则表达式)

字面量模式

var expression = / pattern / flags;

pattern部分可以使任何简单或复杂的正则表达式,可以包含字符类、限定符、分组、先前查找以及反向引用。
flags部分g(全局模式)、i(不区分大小写模式)、m(多行模式)。

使用RegExp构造函数

接收两个参数:一个是要匹配的字符串模式,另一个是可选的标志字符串。

var pattern2 = new RegExp("[bc]at", "i");

正则表达式字面量始终会共享一个RegExp实例,而使用构造函数创建的每一个新RegExp实例都是一个新实例。

RegExp实例属性

  • global:是否设置g标志。
  • ignoreCase:是否设置i标志。
  • lastIndex:表示搜索下一个匹配项的字符位置,从0算起。
  • multiline:是否设置m标志。
  • source:返回正则表达式字符串。

RegExp实例方法

exec(),接收一个参数,要应用模式的字符串,返回包含第一个匹配项信息的数组,没有则null。
包含2个属性,index和input。
index表示匹配项在字符串中的位置。
input表示应用正则表达式的字符串。
在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中捕获组匹配的字符串。

var text = "mom and dad and baby";
var pattern = /mom( and dad( and baby)?)?/gi;
var matches = pattern.exec(text);
console.log(matches.index); //0
console.log(matches.input); //mom and dad and baby
console.log(matches[0]); //mom and dad and baby
console.log(matches[1]); // and dad and baby
console.log(matches[2]); // and baby

**test()**接收一个字符串参数,在模式与该参数匹配的情况下返回true。

正则表达式中方括号的应用

描述
[abc]查找方括号之间的任何字符
[^abc]查找任何不在方括号之间的字符
[0~9]查找任何从0至9的数字

正则表达式中常用字符的含义

描述
/…/代表一个模式的开始和结束
^匹配字符串的开始
$匹配字符串的结束
\s任何空白字符
\S任何非空白字符
\d匹配一个数字字符,等价于[0~]
\D除了数字之外的任何字符
\w匹配一个数字、下划线或字母字符,等价于[AZaz0~9_]
\W任何非单字字符
.除了换行符之外的任意字符

常用量词的含义

描述
*出现0次或连续多次
+出现至少一次
?出现0次或者一次
{n}连续出现n次
{n,}连续出现至少n次
{n,m}至少n次,至多m次

附:子匹配(正则表达式语法中的分组概念),用“()”把字符串括起来,例:var reg=/(ab)c/;

Fuction类型

没有重载!!!声明多个同名函数,下面的会覆盖上面的同名函数,无论是否在下面的函数上面调用,都是执行被覆盖的方法。函数表达式不会出现这种问题。

匿名函数

// 如果想调用匿名函数必须要声明一个变量把函数给它。var 变量 = 匿名函数;
var f2 = function () {	// 函数表达式
    console.log("我是一个匿名函数");
}
f2();	// 匿名函数的调用

函数的自调用(沙箱)

沙箱比喻一个虚拟环境,内部执行结果和外部一样,但互不影响。

(function (){console.log("自调用")})();
(function (){console.log("自调用")}());

预解析(重要)

–提前解析代码。
把变量的声明(它的值不会提前)提前了—提前到当前所在的作用域的最上面。
函数的声明也会被提前—提前到当前所在的作用域最上面。
预解析中,变量的提升,只会在当前作用域中提升,不会出去。

例:

console.log(num);	// 输出undefined;
var num = 10;
或
f1();	// 输出哈哈!!!
function f1() {
    console.log("哈哈!!!");
}

函数作为返回值使用

**PS:**函数作为返回值使用,调用该方法时,必须用函数表达式接收,在调用函数表达式。

function f1() {
    console.log("f1函数调用了");
    return function () {
        console.log("这是一个函数");
    }
}
var ff = f1();
ff();

函数作为参数使用(重要)

函数可以作为参数使用,如果一个函数作为参数,那么这个参数(函数)可以叫回调函数。
只要看到一个函数作为参数使用了,那就是回调函数。

function sayHi(fn) {
    console.log("Hi");
    fn();
}
function say(){
    console.log("我叫Bosco");
}
sayHi(say);

apply()和call()、bind() (重要)

  • apply()方法接收两个参数,一个是在其中运行函数的作用域,另一个是参数数组(Array的实例或arguments对象)。
  • call()方法与apply作用相同,只是其余参数都是直接传递给参数,即要一个个列举出来。
function sum(num1, num2) {
    return num1 + num2;
}
function callsum1(num1, num2) {
    return sum.apply(this, arguments);
    // return sum.call(this, num1, num2);
}
console.log(callsum1(10,10));

他们可以扩充函数赖以运行的作用域,利用传入第一个参数的不同。

  • bind()方法,将this值被绑定到传给bind()函数的值。返回值为对象。它与apply()差不多,只是它是复制之后改变this的指向。例如传入对象。

基本包装类型

|-String、number、boolean。
本身是基本类型,但是在执行代码的过程中,如果这种类型的变量调用了属性或者是方法,那么这种类型就不在是基本类型了,而是基本包装类型,这个变量也不是普通的变量了,而是基本包装类型对象。
使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。而
自动创建的基本包装类型的对象,则只存在于一行代码的执行瞬间,然后立即被销毁。

String对象

​ string—基本类型
String—引用类型
字符串可以看成一个字符数组,可以for循环遍历。
字符串特性:不可变性,字符串的值是不能改变,即不可利用数组加索引的方式修改字符串。
字符串的值之所以看起来是改变的,那是因为指向改变了,并不是真的值改不了。
常用属性和方法:
.length // 获取字符串长度
charAt(index) // 获取指定位置处字符
charCodeAt(index) // 获取指定位置处字符的ASCII码
str[0] // 与charAt()等效
String.fromCharCode(num1,…,numN) // 返回使用指定的Unicode值序列创建的字符串,如\u0031
indexOf(searchValue[, fromIndex]) // 返回调用String对象中第一次出现的指定值的索引,开始在fromIndex进行搜索。
lastIndexOf(searchValue[, fromIndex]) // 返回指定值在调用该方法的字符串中最后出现的位置,如果没找到则返回-1。从该字符串的后面向前查找,从fromIndex处开始。
replace(regexp|substr, newSubStr|function) // 返回一个由替换值替换一些或所有匹配的模式后的新字符串。
search(regexp) // 执行正则表达式和 String对象之间的一个搜索匹配。
split([separator[, 切割后留下的个数]]) // 使用指定的分隔符字符串将一个String对象分割成字符串数组,以将字符串分隔为子字符串,以确定每个拆分的位置。
substring(indexStart[, indexEnd]) // 返回一个字符串在开始索引到结束索引之间的一个子集, 或从开始索引直到字符串的末尾的一个子集。
**详细看:**https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String

单体内置对象

Global对象

  • URI编码方法
    encodeURI()和encodeURIComponent()方法可以对URI进行编码,以便发送给浏览器。
    encodeURI()用于对URI中某一段,且不会对本身属于URI的特殊字符进行编码。
    encodeURIComponent()用于整个URI,对它发现的任何非标准字符进行编码。(常用)
    对应两个解码方法:encodeURI()和encodeURIComponent()。

  • eval()方法(谨慎使用)
    只接收一个参数,传入的参数当作实际的ECMAScript语句来解析,然后把执行结果插入到原位置。被执行的代码具有与该执行环境相同的作用域链。

window对象

在全局作用域中声明的所有变量和函数,就都成为了window对象的属性。
当在全局作用域中调用一个函数时,this对象总是指向Global对象(在浏览器中就是window对象)

Math对象

常用属性和方法:
Math.PI // 圆周率
Math.E // 基数(e)约等于2.718
Math.abs(x) // 返回x的绝对值
Math.ceil(x) // (向上取整)函数返回大于或等于一个给定数字的最小整数。
Math.floor(x) // (向下取整)返回小于或等于一个给定数字的最大整数。
Math.max([value1[,value2, …]]) // 返回一组数中的最大值。

function getMaxOfArray(numArray) {
    return Math.max.apply(null, numArray);
}
var arr = [1,2,3,4,5];
var maxNum =getMaxOfArray(arr);
console.log(maxNum);
或者
var maxNum = Math.max(...arr);	// 较新写法

​ Math.mix([value1[,value2, …]]) // 返回一组数中的最小值。
Math.pow(x,y) //返回基数(x)的指数(y)次幂
Math.sqrt(x) // 函数返回一个数的平方根
Math.random() // 函数返回一个浮点, 伪随机数在范围[0,1)。

// 得到一个两数之间的随机数
function getRandomArbitrary(min, max) {
  return Math.random() * (max - min) + min;
}

实训:

function getColor() {
    var str = "#";
    var arr =["1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];
    for (var i = 0; i < 6; i++) {
		str = str + arr[parseInt(Math.random() * 16)];
    } 
    return str;
}
var sixColor = getColor();
console.log(sixColor);

面向对象(重点)

对象

|-面向对象特性:封装,继承,多态(抽象性)。
|-js不是面向对象的语言,但是可以模拟面向对象的思想。
|-js是一门基于对象的语言。
ECMAScript中有两种属性:数据属性和访问器属性。

数据属性(默认都为true)

  • Configurabele:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
  • Enumerable:表示能否通过for-in循环返回属性。
  • Writable:表示能否修改属性的值。
  • Value:包含这个属性的数据值。
    可以通过Object.defineProperty()修改属性默认的特性,该方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象(数据属性)。
Object.defineProperty(person, "name", {
   writable: false,
   value: "Nicholas"
});

访问器属性

  • Configurabele:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
  • Enumerable:表示能否通过for-in循环返回属性。
  • Get:读取属性时调用的函数。
  • Set:写入属性时调用的函数。
    通过Object.defineProperty()定义
Object.definProperty(book, "year", {
    get: function(){
        return this.year;
    },
    set: function(){
        if(newValue > 2014){
            this.year = newValue;
            this.edition += newValue - 2014;
        }
    }
});

定义多个属性:Object.defineProperties()
读取属性特性:Object.getOwnPropertyDescriptor(),返回一个对象。

创建对象

工厂模式创建对象

function createObject(name) {	// 函数
    var obj = new Object;	// 系统构造函数
    obj.name = name;
    obj.sayHi = function() {
        console.log("我叫" + this.name);
    }
    return obj;
}
var per = createObject("小红");
per.sayHi();

构造函数模式(重要)

构造函数始终都应该以一个大写字母开头,而非构造函数则应该以一个小写字母开头。
|-所有对象均继承自Object.

function Person(name) {	// 函数
    this.name = name;
    this.sayHi = function() {
        console.log("我叫" + this.name);
    }
}
var per = new Person();
per.sayHi();

构造函数的问题:每个方法都要在每个实例上重新创建一次,可使用以下方法来解决。

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
}
function sayName() {
    console.log(this.name);
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
person1.sayName();
var person2 = new Person("Greg", 27, "Doctor");
person2.sayName();
console.log(person1.sayName() == person2.sayName());
判断变量(对象)是不是属于什么类型

语法:变量 instanceof 类型的名字
返回:true or false

原型模式

创建的每个函数都会有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而是这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
好处是可以让所有对象实例共享它所包含的属性和方法。

function Person() {

        }
        Person.prototype.name = "Nicholas";
        Person.prototype.age = 29;
        Person.prototype.job = "Software Engineer";
        Person.prototype.sayName = function () {
            console.log(this.name);
        };

        var person1 = new Person();
        person1.sayName();
        var person2 = new Person();
        person2.sayName();
        console.log(person1.sayName == person2.sayName);
  • 这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。
  • 每当代码读取某个对象的某个属性时,先从实例中搜索,再从原型搜索。
  • 当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性。
    在这里插入图片描述

通过isPrototype()方法来确定对象之间是否存在这种关系

alert(Person.prototype.isPrototypeOf(person1));

Object.getPrototypeOf()返回的对象实际就是这个对象的原型。

alert(Object.getPrototypeOf(person1) == Person.prototype);

使用hasOwnProperty()检测一个属性是存在于实例中,还是存在于原型中。只存在于对象实例中时才返回true。

person1.hasOwnProperty("name");
原型与in操作符

在单独使用时,in操作符会在通过对象能够访问给定属性时返回true.

console.log("name" in person1);

​ 在使用for-in循环时,返回的时所有能通过对象访问的、可枚举的属性,其中既包括存在于实例中的属性,也包含存在原型中的属性。屏蔽了原型的不可枚举属性的实例属性也会在for-in循环中返回。

  • Object.keys()接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。
  • Object.getOwnPropertyNames()得到所有实例属性,无论他是否可枚举。
使用字面量方式创建原型语法(了解)
	 function Person() {

        }

        Person.prototype = {
            name: "Nicholas",
            age: 29,
            job: "Software Enginner",
            sayName: function () {
                console.log(this.name);
            }
        }

本质上完全重写了默认的prototype对象,因此construction属性也就变成新对象的constructor属性(指向Object构造函数),不再指向Person函数。
**可以在里面添加constructor: Person修改其值,不过会导致它的[[Enumerable]]特性被设置为true。**最好使用以下方法修改:

Object.defineProperty(Person.prototype, "constructor", {
   enumerable: false,
   value: Person
});

组合使用构造函数模式和原型模式(重要)

构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。

function Person(name, age, job) {
            this.name = name;
            this.age = age;
            this.job = job;
            this.friends = ["Shelby", "Court"];
        }

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

        var person1 = new Person("Nicholas", 29, "Software Engineer");
        var person2 = new Person("Greg", 27, "Doctor");
        person1.friends.push("Van");
        console.log(person1.friends);
        console.log(person2.friends);
        console.log(person1.friends == person2.friends);
        console.log(person1.sayName == person2.sayName);

稳妥构造函数模式

所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this对象;它类似于寄生构造函数(类似于工厂函数)的模式,但有两点不同:
|-新创建对象的实例方法不引用this。
|-不适用new操作符调用构造函数。

function Person(name, age, job) {
    var o = new Object();
    var name = name;
    var age = age;
    var job = job;
    o.sayName = function () {
        console.log(name);
    }
    return o;
}
var friend = Person("Nicholas", 29, "Software Engineer");
friend.sayName();	// Nicholas,除了调用sayName方法外没有别的方式可以访问其数据成员
console.log(friend.name);	// undefined

继承(重要)

ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的。

原型链(重点理解)

利用原型让一个引用类型继承另一个引用类型的属性和方法。
构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
注意:先改变指向,再向原型中添加方法。
优点:可以使用超类型的原型的方法。

function SuperType(){
    this.property = true;
}
SuperType.prototype.getSuperValue = function(){
    return this.property;
};
function SubType(){
    this.subproperty = false;
}
SubType.prototype = new SuperType();	//继承了SuperType
SubType.prototype.getSubValue = function(){
    return this.subproperty;
};
var instance = new SubType();
console.log(instance.getSuperValue());	//true

在这里插入图片描述
在这里插入图片描述

原型链存在的问题

1.包含引用类型值的原型属性会被所有实例共享。
2.**在创建子类型的实例时,不能向超类型的构造函数中传递参数。**因此很少单独使用原型链。

借用构造函数(伪造对象或经典继承)

在子类型构造函数的内部调用超类型构造函数,通过使用apply()和call()方法在新创建的对象上执行构造函数。
优点:能向超类型的构造函数中传递参数

function SuperType(){
    this.colors = ["red","blue","green"];
   
}
function SubType(){
    SuperType.call(this);	//继承了SuperType
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);	//"red,blue,green,black"
var instance2 = new SubType();
console.log(instance2.colors);	//"red,blue,green"
借用构造函数存在问题

方法都是在构造函数中定义,且在超类型的原型中定义的方法,对子类型而言也是不可见的。

组合函数(重点,常用)

使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
具有原型链和借用构造函数的优点。

function SuperType(name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function () {
    console.log(this.name);
};
function SubType(name, age) {
    SuperType.call(this, name, age);    //继承属性,第二次调用SuperType
    this.age = age;
}
SubType.prototype = new SuperType();    //继承方法
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function () {
    console.log(this.age);
};
var instance1 = new SubType("Nicholas", 29);  //第一次调用SuperType
instance1.colors.push("black");
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();
var instance2 = new SubType("Greg", 27);
console.log(instance2.colors);
instance2.sayName();
instance2.sayAge();

**存在问题:**无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。

原型式继承

借助原型基于已有的对象创建新对象,同时还不必因此创建自定义类型。不过包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样。
**Object.create()**方法接收两个参数:一个用作新对象原型的对象和一个为新对象定义额外属性的对象(可选);ECMAScript5新增方法。

var person = {
    name : "Nicholas",
    friends: ["Shelby","Court","Van"]
};
var anotherPerson = Object.create(person, {
    name: {
        value: "Greg"
    }
});
console.log(anotherPerson.name); //Greg
//另一种方法,类似Object.create()
function object(o){
    function F(){}
    F.prototype = o;
    return new F();
}
var anotherPerson = object(person);

寄生式继承

类似寄生构造函数和工厂模式类似。
前面是否继承模式时使用的object()函数不是必需的;任何能够返回新对象的函数都适用于此模式。

function createAnoter(original) {
    var clone = object(original);
    clone.sayHi = function () {
        console.log("hi");
    };
    return clone;
}
var person = {
    name: "Nicholas",
    friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = createAnoter(person);
anotherPerson.sayHi(); //hi

缺点:不能做到函数复用。

寄生组合式继承(重点)

通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

//使用到上面的object()
function inheritPrototype(subType, superType) { //重点代码
    var prototype = object(superType.prototype); // 创建超类型副本
    prototype.constrictor = subType; // 弥补重写原型而失去的默认的constructor属性
    subType.prototype = prototype; // 将副本赋值给子类型的原型
}
function SuperType(name) {
    this.name = name;
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function () {
    console.log(this.name);
};
function SubType(name, age) {
    SuperType.call(this, name)
    this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function () {
    console.log(this.age);
};
var instance1 = new SubType("Nicholas", 29);  
instance1.colors.push("black");
console.log(instance1.colors);
instance1.sayName();
instance1.sayAge();

函数表达式

定义函数的方式有两种:一种是函数声明,另一种是函数表达式。
1.函数声明;特征具有预解析。

function functionName(arg0,arg1,arg2){
    //函数体
}

2.函数表达式(常用),也叫匿名函数,不存在预解析。
var functionName = function(arg0, arg1, arg2){
//函数体
};

递归

arguments.callee是一个指向正在执行的函数的指针,可以用来实现对函数的递归调用。

function factorial(num){
    if(num <= 1){
        return 1;
    }else{
        return num * arguments.callee(num-1);
    }
}

闭包(重点,需了解)(点赞功能)

闭包是有权访问另一个作用域中的变量和函数。
闭包在匿名函数执行完毕后,其活动对象也不会被销毁,仍留在内存中(缓存数据)。因此使用后要销毁(等于null)对匿名函数的引用。
例:

function createComparisonFunction(propertyName) {
    return function (object1, object2) {
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
    }
    if (value1 < value2) {
        return -1;
    } else if (value1 > value2) {
        return 1;
    } else {
        return 0;
    }
}
var compareNames = createComparisonFunction("name");
var result = compareNames({name: "Nicholas"},{name: "Greg"});
compareNames = null;

在这里插入图片描述
**注意:**闭包只能取得包含函数中任何变量的最后一个值,因为闭包所保存的是整个变量对象。

this对象

this对象是在运行时基于函数的执行环境绑定的;不过匿名函数的执行环境具有全局性,因此其this对象通常指向window。

解决内存泄漏

闭包会引用包含函数的整个活动对象,而其中包含着element。即使闭包不直接引用element,包含函数的活动对象中也仍然会保存一个引用。因此,有必要把element变量设置为null。

模仿块级作用域

JavaScript没有块级作用域的概念,因为JavaScript从来不会告诉你是否多次声明了同一个变量,它遇到后续同名的声明只会视而不见,可查看前面的“没有块级作用域”。
私有作用域(函数的自调用)

(function (){
    //这里是块级作用域
})();

函数调用会立即销毁。

私有变量和公共属性

  • 私有属性:在函数内部使用var声明的属性。
  • 公共属性:在函数内部使用this、对象或者直接写名字(不推荐使用匿名全局变量)。
  • 有权访问私有变量和私有函数的公有方法称为特权方法。比如getter和setter方法。

静态私有变量

通过原型来设置特权方法。

(function(){
    var name = "";
    Person = function(Value){
        name = value;
    };
    Person.prototype.getName = function(){
        return name;
    };
    Person.prototype.setName = function(value){
        name = value;
    };
})();

模块模式

模块模式则是为单利创建私有变量和特权方法。所谓单例就是只有一个实例的对象。
JavaScript是以对象字面量的方式来创建单例对象的。
通常用于需要对单例进行某些参数,同时又需要维护其私有变量的时候用。

var singleton = function(){
    var provateVariable = 10;
    function privateFunction(){
        return false;
    }
    return {
        publicProperty: true,
        publicMethod: function(){
            privateVariable++;
            return privateFunction();
        }
    };
}();

增强的模块模式

适合单例必须要某种类型的实例,同时还必须添加某些属性或方法对其加以增强的情况。

var singleton = function(){
// 私有变量和私有函数
    var provateVariable = 10;
    function privateFunction(){
        return false;
    }
    var object = new CustomType();
    // 添加特权/公有属性和方法
    object.publicProperty: true,
    object.publicMethod: function(){
            privateVariable++;
            return privateFunction();
    };
    return object; //返回对象
}();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值