1、什么是对象
“对象"说白了就是一个实实在在的‘物件’或者说是‘东西’,正儿八经地存在于自然界中的或者有依有据想象的到的实物,之所以要在编程世界里创造出对象(面向对象的编程)主要就是便于人类的理解。计算机本身是不会理解什么是面向过程什么是面向对象,计算机只会机械地执行一条一条的指令。就像雕刻大师用他精湛的刀工去创作一尊美艳绝伦的雕像,雕像的的形态存在于大师的脑子里,最后存在于自然界里,但那把刀即便再关键它也不会针对这尊雕像有任何思想。计算机是人造的,人当然可以站在计算机的角度去编程,最原始的编程方法不就是这样,但人和计算机还是有所不同,人的思想是发展的,而计算机还是再执行一条一条的命令,它改变的只是执行的速度。速度快了干的事更多了,我们就可以将计算机语言一层一层的抽象出来,而每一层都有特定的层序去干特定的事,层层嵌套层层包装最后越来越接近人类更容易理解的方式,而面向对象也就由此而生。
2、javascript中的函数
要想了解对象首先要知道什么是函数。
function Person(name, sex){
name = name;
this.sex = sex;
console.log(arguments);
}
函数是一个程序块,除了汇编外大数编程语言中都有函数的定义,而js中的函数调用方式也无它二,以上代码通过调用
Person("张三","男")
执行程序。
看一下js函数的特点上面的代码可以看到一个关键词this
和一个变量arguments
,this其实是对象中才有的东西,这里this指向调用该函数的对象,现在不必关心这个东西。arguments是一个对象,可以通过typeof arguments
命令查看。从字面上看arguments应该是包含传入函数的形参。
观察arguments对象中的内容的确包含了形参内容,并且还有4个参数
length
代表形参个数
callee
指向了函数本身(常用于递归)
[[Prototype]]
指向arguments的父对象Object
Symbol(Symbol.iterator)
迭代器Symbol
关于 callee
function Person(name, sex){
this.name = name;
this.sex = sex;
function say(){
console.dir(say == arguments.callee);
console.dir(arguments.callee);
console.dir(arguments.callee.caller);
console.dir(arguments.callee.arguments);
}
say();
}
say
与arguments.callee
相等说明他们指向了相同的函数体,它们具有相同的属性(红框中的内容)。
caller
指向当前函数的调用者函数 caller与此处的arguments都是运行时参数。
[[Prototype]]
指向Funtion函数(可见Prototype不仅能指向对象也能指向函数)
prototype
这是一个比较重要的属性指向了一个对象,对象中一个构造函数,一个父对象。
关于 prototype
prototype翻译过来是原型的意思,在js中特指对象的原型。prototype对象是js实现面向对象的一个重要机制。
prototype代表了该函数的原型,还表示了一个类的属性的集合。。
当用new来生成一个对象时,prototype对象的属性将会成为实例化的对象的属性
3、javascript中的对象
在 JavaScript 中,几乎“所有事物”都是对象。
- 布尔是对象(如果用 new 关键词定义)
- 数字是对象(如果用 new 关键词定义)
- 字符串是对象(如果用 new 关键词定义)
- 日期永远都是对象
- 算术永远都是对象
- 正则表达式永远都是对象
- 数组永远都是对象
- 函数永远都是对象
- 对象永远都是对象
所有 JavaScript 值,除了原始值,都是对象。
原始值指的是没有属性或方法的值。
原始数据类型指的是拥有原始值的数据。
JavaScript 定义了 5 种原始数据类型: - string
- number
- boolean
- null
- undefined
原始值是一成不变的(它们是硬编码的,因此不能改变)。
JavaScript 提供用于原始对象的构造器:
var x1 = new Object(); // 一个新的 Object 对象
var x2 = new String(); // 一个新的 String 对象
var x3 = new Number(); // 一个新的 Number 对象
var x4 = new Boolean(); // 一个新的 Boolean 对象
var x5 = new Array(); // 一个新的 Array 对象
var x6 = new RegExp(); // 一个新的 RegExp 对象
var x7 = new Function(); // 一个新的 Function 对象
var x8 = new Date(); // 一个新的 Date 对象
JavaScript 提供原始数据类型字符串、数字和布尔的对象版本,因此没有理由创建复杂的对象。因为原始值快得多
请使用对象字面量 {} 代替 new Object()。
请使用字符串字面量 "" 代替 new String()。
请使用数值字面量代替 Number()。
请使用布尔字面量代替 new Boolean()。
请使用数组字面量 [] 代替 new Array()。
请使用模式字面量代替 new RexExp()。
请使用函数表达式 () {} 代替 new Function()。
JavaScript 对象是命名值的集合。值按照名称 : 值对的形式编写(名称和值以冒号分隔)。
var car = {type:"porsche", model:"911", color:"white"};
以上代码在js中就会声明成一个对象,如果你之前接触过JSON那么也许你会说js过于随意,竟然直接把json当作对象,这不是js偷懒而是json本身就是因js而生的,只是这种格式比较不错,应用于很多场合,也许你没有接触js但很早就熟悉json了,但两者之间并不是一种事物,对象是机器能够识别的指令,它是程序的一部分,计算机认识它。而json只是一种数据格式,更确切说是计算机传输过程中的一串字符,计算机本身是不认识它的。
var car = {type:"porsche", model:"911", color:"white",getClolor: function(){return "red";}};
这段代码很明显看出与json的不同,对象里不仅包含了属性,还包含动作(方法)。这样看对象更像一个"物件"了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-InxkclAh-1649923827949)(en-resource://database/1652:1)]
打印了这个对象,对象中不仅有我们定义的方法他还从Object对象继承了一些属性和方法, Object对象是所有对象的顶级父对象。
图中有两个长相奇怪的函数我用红色框标记出来的地方,这是ECMAScript 5 (2009) 引入了 Getter 和 Setter。它可以将函数绑定到属性上,当属性被调用时函数也被调用。
var car = {type:"porsche", model:"911", incolor:"white",
get color(){
return this.incolor;
},
set color(col){
this.incolor = col;
},
};
>car.color // 调用color时调用get里的函数
>'white'
>car.color = "blue" //给color赋值时执行set函数
除了直接声明对象,还可以使用构造器的方式创建对象。
function Person(first, last, age, eye) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eye;
}
以上我们创建了一个构造器,构造器可以是有参构造器也可以是无参构造器。看到这里也许有些同学会疑惑这明明就是一个函数,怎么就成对象构造器了?是的这里可以把它作为一个函数,因为构造器本身就是一个函数。你也可以当作函数来使用。但只要稍微改动一下就没法再当作普通函数使用了,看下面代码
function Person(first, last, age, eye) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eye;
this.getCname = function(){
return this.firstName;
}
}
此时再当作函数来用就无法调用到
getCname
方法了,此时我们的思想也要转变一下,该函数已不再是一个单纯的函数而是一个对象类型或者叫“蓝图”或“类”。要用这个对象类型就要使用new
关键字。
var person = new Person();
关键字的作用并不是显示地去执行一段代码,而是编译器或解释器或处理器已经定义了一套程序模板,当程序看到关键字的时候就会调用这套模板
new做了什么
- 创建一个新对象
- 将构造函数的作用域赋值给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
模拟new
function Person(name, sex){
this.name = name;
sex = sex;
this.say = function(){
console.log(this.name);
}
}
function instance(Func, ...args){
var o = new Object();
o.__proto__ = Func.prototype; // 将构造函数的原型对象赋值给新建对象的 隐式原型
const result = Func.call(o, ...args); // 执行构造函数并将构造函数里面的this指向新建对象obj
return typeof result === 'object' ? result : o // 如果 执行结构是一个对象,那么就返回执行结果 否则返回新建对象
}
window.onload = function(){
var person = instance(Person, "张三", "男");
console.log(person.say)
}
call()
方法是预定义的 JavaScript 方法。它的作用是调用一个对象的一个方法,以另一个对象替换当前对象。用人话说就是call函数实现了一种方法,可以让对象在不改变内部结构的情况下扩展出其他自身不存在的方法。看个简单的例子
var math = {
sub:function(a, b){
return a-b;
}
}
function add(a, b){
return a+b;
}
window.onload = function(){
let sum = add.call(math, 1,2);
}
对象math中没有add()方法我们通过call方法将add动态地传递给了math对象,不得不说这真实一种创新。我们知道通俗上讲继承的意义就是扩展父类的方法和属性,上面代码正好是对象的扩展,由此可以通过这种方式实现继承。
function Person(){
this.say = function(){
console.log("hello");
}
}
function Student(){
Person.call(this); // 将Student的对象this替换掉Persion中的this,say方法就自然被赋值到studnet的对象上了。
this.study = function(){
console.log("学习好快乐");
}
}
window.onload = function(){
let student = new Student();
student.say();
}
new 方法中的call与此处的原理相同,这也就是为什么构造函数中的属性都要添加"this."
目的是为了子对象使用。