js中对象的分类
对象的分类:
1.内置对象:由ECMA实现 的,不依赖于宿主环境的对象,这些对象在js程序执行之前就已经存在了。
本地对象:Object,Array,String,Number,Boolean,Date等。
单体内置对象:只有两个Global,Math。与本地对象的区别在于:不需要加new 。
2.宿主对象:就是js寄宿环境定义的对象。
在浏览器端的js而言,宿主对象就是浏览器对象。例如:window,document,history等。
Global对象:定义的全局变量,全局函数,其实就是这个对象的属性。
其它的本地对象其实也是它的属性。从这个意义上讲,Global东西相当于是js程序运行总管。
3.自定义的对象
window对象
window是Global对象在浏览器端的代言人。换句话说,在浏览器端编写js程序,就直接可以使用window来代替global。(如果你在你服务器端,在node.js中global对象是真实存在的)。
定义的任何全局变量,函数,都是window对象的属性。
var a = 1,
b = 2;
console.log(window.a) //1
console.log(window.b) //2
但是在使用中window可以省略。
js的三条定律
一切都是对象
1.基本数据类型也当作对象处理
var string = 'dabao';
console.log(string.length);
string为基本数据类型,但是他同样有方法,在运行过程中js会把它临时转变成一个包装类的对象。
var string = new String('dabao')
2.引用类型的数据也是对象
函数:
function f(){}
console.log(f);
console.log(f instanceof Object) //true
Paste_Image.png
数组:
给数组添加新属性,一定要按下标的序号规则去加,如果下标是字符串(正确的下标应该是数字),则length的值不会增加,但,添加的属性确定是添加成功。
var a = [1,2,3];
a.name = 'dabao';
a[3] = 'xiaobao';
Paste_Image.png
对象自然也是对象。
属性操作
四个特征:
configurable:是否可以删除。默认为true。
writable:是否可以修改属性的值。默认为true。
enumerable:是否可以枚举。是否可以通过for in 循环来输出。默认为true。
Value:值。默认为undefined。
Object.defineProperty(对象名,“属性名”,{
Configurable:
Writable:
Enumerable:
Value:
})
var obj = {}
Object.defineProperty(obj,"name",{
configurable:false,
writable:false,
value:'dabao'
})
console.log(obj)
obj.name = 'xiaobao';
console.log(obj.name)
delete obj.name;
console.log(obj);
Paste_Image.png
函数被调用次数的例子
function f(){
f.counter++;
}
f.counter = 0;
f();
f();
f();
console.log(f.counter) //3
深入理解var 与不加var 的区别
a = 1;
console.log(a); //1
var b = 2;
console.log(b); //2
delete a;
delete b;
console.log(window.a); //undefined
console.log(window.b); //2
遗漏声明变量就是window对象的属性,是可以被删除的。而加var声明是不可删除的。为什么呢?因为使用var添加的属性有一个特性是:configurable:true;
对象是由函数创造
var array = new Array(1,1)
var f = new Function('x','y','return x+y');
var n = new Number(1)
var obj = new Object();
无论是数组还是函数还是基本数据类型都是由函数创建的。
原型与原型链
prototype就是原型,__ proto__ 称为隐式原型。前后有两个下划线。它对外是隐藏的,我们在程序开发过程,不会直接使用它。
1.函数都有一个prototype属性
每个函数,都会有很多属性(因为函数也是对象,而对象是属性的集合),其中一定有一个prototype属性。
函数的prototype属性是一个对象,这个对象中有很多方法。但是一定有一个方法:constructor,constructor指向 这个函数本身。
(在es6的语法中,使用class创建类,实际上每个类都有一个constructor,即使你不设置,也会默认存在)
2.每一个对象都有一个__ proto__属性
对于函数而言,也是对象,所以函数都会有一个prototype和一个__ proto__属性。
对象的__ proto__属性指向创建这个对象的函数的prototype。
function F(){
this.name = 'dabao'
}
var f = new F();
console.log(F.prototype)
console.log(f.__ proto__)
Paste_Image.png
如果访问一个对象的属性时,先在这个对象自己的属性中去找,如果找不到,则沿着__ proto__这个属性找,如果__ proto__这个对象中还是没有找到,就在__ proto__对象的__ proto__属性中去找,依次下去,这就是原型链。
也就是说,当我们访问对象,会寻找自己的属性,当找不到自己的属性时,就去找自己的隐式原型__ proto__,__ proto__指向创建该对象方法的prototype,prototype实际上也是一个对象,它也有一个__ proto__这样会继续往上一级找。
由于对象的__ proto__[隐式原型]与创建这个对象的函数(构造器)的prototype是一致的。
所以理论上,你对__ proto__修改会直接影响prototype。
建议你只使用prototype[原型]
创建对象
字面量方法
var obj = {
name : 'dabao',
say : function(){
console.log(this.name)
}
}
工厂模式
function creatObj(){
var obj = {}
obj.name = 'dabao';
obj.say = function(){
console.log(this.name)
}
return obj;
}
构造器模式
function F(){
this.name = 'dabao'
}
var f = new F()
到底做了什么? 为什么给一个函数加一个new 就能产生对象呢?
new一共做了如下四件事:
1.创建一个对象 var obj = {}
2.F.call(obj);先执行F()函数,同时把this用obj来代替。把F()构造器设置的各种属性值,直接赋给o.
3.obj.__ proto__ = F.prototype
4.返回 obj;
原型模式
function F(){
this.name = 'cxh'
}
F.prototpe.say = function(){}
将方法写在原型上。
注意:不要去修改对象的__ proto__。会导致由构造器所产生的全部的对象的属性都会受到影响。
覆盖prototype的问题:
因为prototype里面肯定有一个contructor方法,假如采用直接覆盖的方法,将把当前的对象的构造器归置为object。
我们可以采用jq的方法
重新设置 constructor。
继承
js特点:生来继承
Var s ={};
s.toString();//为什么有toString()?从__ proto__获取的。
1.原型继承
function Parent(){}
function Son(){}
Son.prototype = Parent.prototype
Son.prototype.constructor = Son
2.类式继承
function Parent(name){
this.name = name
}
function Son(name,newName){
this.newName = newName;
Parent.call(this,name)
}
针对属性使用 类式继承
针对方法是用原型继承
使用es6 extends继承。
继承方式可以有很多种,但是无论哪种,都是
子类属性即父类的属性
子类的方法继承父类的方法
即
son.__ proto__ = parent
son.prototype.__ proto__ = parent.prot0type
网友评论