目录
前言
刚开始学习JavaScript的时候感觉原型是一个非常难以理解的东西,现在大致对对象和原型链有了一些基本的认知,记录下来。
一、对象
ECMAScript中的对象其实就是一组属和方法的集合
1.创建对象
创建对象一般有两种方法:
1)使用构造函数创建 new Object()
var person = new Object();
person.name="moon",
person.age=22;
2)使用对象字面量表示法
不同属性之间用逗号分割,属性名和属性值之间用冒号分割
var person = {
name:"briup",
age:22
};
2.访问对象属性
1.点表示法,要求右侧必须是以属性名称命名的简单标识符
例如:person.name
2.中括号表示法,中括号中必须是一个计算结果为字符串的表达式,可以通过变量访问属性,如果属性名中含语法错误的字符,或者属性名使用的是关键字或保留字,可以使用中括号
例如:person["first name"]
可以通过点表示法或者中括号表示法为对象添加属性或者为属性重新赋值。
3.删除属性
delete只是断开了属性和宿主对象的联系,而不会操作属性中的属性,并且delete只会删除自有属性,不能删除继承属性。在销毁对象时,为了防止内存泄露,遍历对象中的属性,一次删除所有属性。
语法:delete 属性访问表达式
例如: delete stu.name //删除学生对象中的name属性。
如果里边还有对象,对象还有属性,应该先把里边的属性删了,再删外部的属性。
对象数据的删除?
1.先遍历delete 属性
2.再对象=null,如果对象里边还有对象则应该先删除内部的对象。
4.检测属性
in 检测某属性是否是某对象的自有属性或者是继承属性,如果是就返回true,如果不是就返回false
var obj = new Object();
// Object.prototype.say=function(){};
// obj.say=function(){};
// obj.name='moon';
console.log(obj);
console.log("name" in obj);//false
console.log("say" in obj);//false
console.log("__proto__" in obj);//true
hasOwnProperty()检测给定的属性是否是对象的自有属性,对于继承属性将返回false
propertyIsEnumerable() 检测给定的属性是否是该对象的自有属性,并且该属性是可枚举的,通常由JS代码创建的属性都是可枚举的,但是可以使用特殊的方法改变可枚举性。
例如:
var o = {
x:1
}
o.hasOwnProperty("x"); //true,x 为o的自有属性
o.hasOwnProperty("y"); //false,o 中不存在属性y
o.hasOwnProperty("toString"); //false,toString为继承属性
o.propertyIsEnumerable(“toString”); //false,不可枚举
o.propertyIsEnumerable(“x”); //true
5.Object的原型属性及方法
Object 类型所具有的任何属性和方法也同样存在于其他对象中,任何对象继承于Object对象。
Object原型中常用的属性和方法
constructor: //保存用户创建当前对象的函数
hasOwnProperty('propertyName'); //检查给定的属性名是否是对象的自有属性,
toString(); //返回对象的字符串表示,如果不重写就是"[object Object]"
valueOf(); //返回指定对象的原始值,object返回对象本身
propertyIsEnumerable('propertyName'); //检查给定的属性是否是该对象的自有属性,并且可枚举
isPrototypeOf(object); //用于测试一个对象是否存在于另一个对象的原型链上
例:
var obj= new Object();
Object.prototype.isPrototypeOf(obj);//true
6.对象序列化
对象序列化是指将对象的状态转换为字符串,也可以反序列化,将字符串还原为对象函数,RegExp,Error对象,undefined值不能序列化和反序列化。
JSON.stringify(obj) //将对象序列化为Json字符串,只能序列化对象可枚举的自有属性。
JSON.parse(jsonStr)//反序列化
var obj = new Object();
Object.prototype.say='moon';
obj.name='moon';
obj.age=22;
var j=JSON.stringify(obj);
console.log(j);//{"name":"moon","age":22} JSON格式
var o=JSON.parse(j);
console.log(o);//{name: 'moon', age: 22}
二、函数
1.函数定义
函数定义有两种方法
1.函数声明
function 函数的名称(形参){
函数体;
return//如果没有return就没有返回值
}
return代表函数的结束,函数中return中后面的代码不被执行
2.函数表达式
var 变量名=function(形参){
函数体
}
2.函数的作用和使用
作用:提高复用率,实现代码的封装,作为构造函数
使用:
//函数声明方式
function test1(){
console.log('test1');
}
function test1(){
console.log('第二次test1');
}
test1();//第二次test1
//函数表达式方式
var test2=function(){console.log("1111");};
var test2=function(){console.log("2222");};
test2();//2222
第一个结论:函数变量可以重复定义,重复使用
console.log(say);//[Function say]
say();//可以执行 say
function say(){console.log('say')};
var say='name';
console.log(say);//name
//say();//error!
第二个结论:函数提升,会提升到到作用域的最前边。
3. 函数的内部属性
只有在函数内部才能访问的属性
arguments:是类数组对象,包含着传入函数中参数(实参)
arguments对象中还有一个callee属性,它可以用于引用该函数的函数体内当前正在执行的函数。
arguments.length 显示实参的个数
this:指向的是函数赖以执行的环境对象
就近原则:函数内部--》该文件内部---》运行环境global window
4.函数的属性和方法
函数本质上也是一种对象,拥有属性和方法
length:function.length表示函数希望接受的命名参数的个数,即形参的个数
call((执行环境对象,实参列表)
apply(执行环境对象,实参列表数组)
call与apply的功能与区别 :
反建立函数与对象之间的关系,apply实参是数组
函数的应用:函数本质是一种对象,可以将其当作普通对象来使用。
作为参数:由于函数名本身就是变量,所以函数可以当做值来使用(参数,返回值)。
作为返回值():
function getFunction(){
return function(){
alert(hello);
}
}
变量提升和函数提升的区别:
函数提升更明显
函数提升比变量更前
函数表达式没有函数提升
闭包:函数内部包裹函数,作用域链得不到释放,造成消耗内存
在js作用域环境中访问变量的权利是由内向外的,内部作用域可以获得当前作用域下的变量并且可以获得包含当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的函数作用域中也是不能相互访问彼此变量的,那么我们想在一个函数内部也有权限访问另一个函数内部的变量该怎么办呢?闭包就是用来解决这一需求的,闭包的本质就是在一个函数内部创建另一个函数。
闭包有3个特性:
①函数嵌套函数
②函数内部可以引用函数外部的参数和变量
③参数和变量不会被垃圾回收机制回收
好处
①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
③匿名自执行函数可以减少内存消耗
坏处
①其中一点上面已经有体现了,就是被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响
解决方法:
立即执行函数,创建函数后就立即执行
IIFE
- 页面加载完成后只执行一次的设置函数。
- 将设置函数中的变量包裹在局部作用域中,不会泄露成全局变量。
三、原型链
1.栈和堆
在JS中,栈用来存放基本数据类型的变量和值,引用数据类型的变量和地址值。
var a=100;
var str="hello world";
var obj=new Object();
obj.name="moon";
obj.age=18;
以上面代码为例,栈堆内存如图
2.原型对象
在JavaScript中,每个函数都有其原型对象,在每个函数都有一个特殊的属性prototype,这个属性指向了函数的原型,在这个原型里保存了一些属性方法,其中,原型对象中的constructor属性又指回了构造函数,我们可以说,构造函数和原型对象是成对出现的,构造函数的实例可以直接使用原型方法。以1.栈和堆中的例子来看一下原型对象的情况。

Object()构造函数中prototype属性指向了Object.prototype,Object.prototype中保存了一个constructor属性,指向了构造函数。
obj是Object()构造函数的一个实例,却不直接与构造函数发生联系,而是通过一个__proto__属性指向了原型对象。
3.什么是原型链
像上节所说的,每个实例对象内部都有一个__proto__属性指向原型对象,而原型对象也可能有一个__proto__属性指向它的原型对象,并从中继承方法和属性,这样一层一层的指向,就是原型链。它解释了为何一个对象会拥有定义在其他对象中的属性和方法。
所以,上节图片中红色的箭头所形成的链式结构就是我们所说的原型链。
总结
在JavaScript中,万物皆对象,所以Object.prototype是最顶层的原型对象,其__proto__为null,
构造函数与原型对象成对出现,通常称构造函数为实例的母亲,原型对象为实例的父亲,实例总是继承父亲的属性和方法,父亲可能还会有父亲,在实例和父亲中形成了原型链的关系。
本文详细讲解了JavaScript中对象的创建、属性操作、原型链、函数定义及其内部机制,包括原型对象、原型链的概念,以及对象序列化。深入理解了构造函数、原型链如何构建对象间的关系。
837

被折叠的 条评论
为什么被折叠?



