众所周知,在 js 中对象就是精髓,不理解对象就是不理解 js。
那么什么事 js 中的对象呢?
在 js 中,几乎一切皆对象:
JS 中,所有值,除了原生值,都是对象;这些原生值包括:strings,numbers('3.14'),true,false,null 和 undefined
对象是包含变量的变量,js 变量可以包含单个值,比如:
- var person = "John Doe";
同样,对象也是变量,但它可以包含很多的值,只不过这些值是以键值对的形式表现的 (name and value separated by a colon),一个 js 对象就是命名值的集合。
- var person = {
- firstName: "John",
- lastName: "Doe",
- age: 50,
- eyeColor: "blue"
- };
对象属性
被命名的值,在 js 对象中被称为属性;这种以命名值而写的对象的写法类似于:
- Property Value firstName John lastName Doe age 50 eyeColor blue
对象方法
方法是表现在对象上的行为或动作,对象属性可以是原生值,别的对象,或者函数。一个对象的方法是一个对象包含一个函数定义的属性。
- fullName
- function() {
- return this.firstName + " " + this.lastName;
- }
js 对象是一个包含所谓属性的名值对和方法的容器。
创造一个 js 对象
在 js 中你可以定义和创造自己的对象,有不同的方法去创造对象:
对象字面量方法:最简单,一句话定义并创造一个对象。对象字面量是键值对用大括号抱起来的系列。
- var person = {
- firstName: "John",
- lastName: "Doe",
- age: 50,
- eyeColor: "blue"
- };
new 关键字方法:
- var person = new Object();
- person.firstName = "John";
- person.lastName = "Doe";
- person.age = 50;
- person.eyeColor = "blue";
以上两种例子几乎类似,没必要用 new Object()。为了简洁,可读性及执行性能,首选第一种(对象字面量方法)。
对象构造器
以上两种方法在很多情境中有局限,它们只是创造一个单一对象。有时候,我们喜欢拥有一个可以创造很多一种类型对象的 "对象类型",此时利用对象构造函数创造一个对象类型的标准方式应运而生。
- function person(first, last, age, eye) {
- this.firstName = first;
- this.lastName = last;
- this.age = age;
- this.eyeColor = eye;
- }
- var myFather = new person("John", "Doe", 50, "blue");
- var myMother = new person("Sally", "Rally", 48, "green");
以上方法是一个对象构造器,一旦拥有了它,你可以创造同类的对象
- var myFather = new person("John", "Doe", 50, "blue");
- var myMother = new person("Sally", "Rally", 48, "green");
This 关键字
在 js 中,被称作 this 的东西,是一个 "拥有"js 代码的对象。this 的值,当用在一个函数里,是一个 "拥有" 函数的对象;当用在一个对象里,是对象本身。this 关键字,在一个对象构造器里边没本身有值,仅仅是新对象的替代品。当构造器被用于构造对象时 this 的值会变成新对象。
注意:this 不是一个变量,它是关键字,你不能改变 this 值。
js 用于内置的原生对象的构造器
- var x1 = new Object(); // A new Object object
- var x2 = new String(); // A new String object
- var x3 = new Number(); // A new Number object
- var x4 = new Boolean(); // A new Boolean object
- var x5 = new Array(); // A new Array object
- var x6 = new RegExp(); // A new RegExp object
- var x7 = new Function(); // A new Function object
- var x8 = new Date(); // A new Date object
Math()对象不在列表中,因为 Math 是一个全局对象,new 关键字不能用在 Math 中。
并且,众所周知,js 拥有原生数据类型 String,Number, 和 Boolean 的对象版本。没理由创造浮躁对象,原生值执行的更快。
- var x1 = {}; // new object
- var x2 = ""; // new primitive string
- var x3 = 0; // new primitive number
- var x4 = false; // new primitive boolean
- var x5 = []; // new array object
- var x6 = /()/ // new regexp object
- var x7 = function() {}; // new function object
JS 对象是可变的
对象可变,他们靠索引定位而非值。如果一个 person 是一个对象,那么以下语句不会创造 person 的副本。
- var x = person; // This will not create a copy of person.
对象 x 不是 person 的副本,它是 person 本身,因此任何 x 的改变都很改变 person。
js 变量不可变,可变(Mutable)的只是 js 对象,如下实例。
- var person = {
- firstName: "John",
- lastName: "Doe",
- age: 50,
- eyeColor: "blue"
- }
- var x = person;
- x.age = 10; // This will change both x.age and person.age
对象属性
属性是 js 对象中最重要的部分
访问 js 属性语法:
- objectName.property // person.age
- objectName["property"] // person["age"]
- objectName[expression] // x = "age"; person[x],表达式必须等于属性名
- person.firstname + " is " + person.age + " years old.";
- person["firstname"] + " is " + person["age"] + " years old.";
for-in 循环遍历对象属性语法:
- for (variable in object) {
- code to be executed
- }
添加属性
- person.nationality = "English";
但你不能用保留字作为属性名,利用 js 命名规则。
删除属性
- var person = {
- firstName: "John",
- lastName: "Doe",
- age: 50,
- eyeColor: "blue"
- };
- delete person.age; // or delete person["age"];
删除关键字删除了属性值和其本身,删除后属性在其被再添加之前不能再用。删除操作符被用于对象属性的操作,对于变量或者方法无效。但谨记,delete 操作符不应用于预定义 js 对象的属性,这样会阻塞应用。
属性的属性(property attributes)
属性有个 name,也有一个 value。value 是属性的属性之一,其它属性是:enumerable,configurable,writable。这些属性定义了属性是如何被访问的(是否可读可写)
在 js 中,所有属性是可读的但只有 value 的属性可以被改变(当且仅当属性是可写的)。ES5 中有针对 getting 和 setting 所有属性的属性的方法。
原型属性
js 对象继承它们原型的属性,delete 关键字不删除所继承的属性,但是如果你删除了原型的属性,这将影响所继承原型的所有对象。
对象方法
如前所述,js 方法是对象中表现的行为。js 方法是包含函数定义的属性,即方法是存做对象属性的函数。
访问对象方法:
- methodName: function() {
- code lines
- } //创造一个对象方法
- objectName.methodName(); //访问
- name = person.fullName(); //fullName属性当以()调用时将执行
- name = person.fullName; //fullName当么有()调用时将返回函数定义
利用内置方法
- var message = "Hello world!";
- var x = message.toUpperCase(); //HELLO WORLD!
添加方法(类似于添加属性)
- function person(firstName, lastName, age, eyeColor) {
- this.firstName = firstName;
- this.lastName = lastName;
- this.age = age;
- this.eyeColor = eyeColor;
- this.changeName = function(name) {
- this.lastName = name;
- };
- }
对象属性
所有 js 对象拥有一个原型(prototype),原型也是对象。所有 js 对象继承其原型的属性和方法。
利用字面量或者 newObject 构造的对象,继承所谓的 Object.prototype 的原型;
利用 new Date() 构造的对象继承 Date.prototype.Object.prototype 出于原型链的顶端(top)
因此所有的 js 对象继承自 Object.prototype。
创造一个原型
标准方法是利用一个构造函数去创造一个对象原型:
- function Person(first, last, age, eyecolor) {
- this.firstName = first;
- this.lastName = last;
- this.age = age;
- this.eyeColor = eyecolor;
- }
有了构造函数,你可以利用 new 关键字去从同样原型中创造新对象。
- var myFather = new Person("John", "Doe", 50, "blue");
- var myMother = new Person("Sally", "Rally", 48, "green");
- //构造函数是Person对象的原型,首字母大写去命名构造函数是一个好惯例
给对象添加属性和方法
有时你想添加新属性或方法给一个存在的对象,给所有给定类型的存在对象,或者给一个对象原型。
- myFather.nationality = "English"; //给一个存在的对象,仅仅对此对象
- myFather.name = function() {
- return this.firstName + " " + this.lastName;
- }; //添加一个方法,仅仅对此对象
给原型添加属性
- Person.nationality = "English"; //不能像给已存在对象添加新属性那样给原型添加,因为原型不是一个存在的对象。
- function Person(first, last, age, eyecolor) {
- this.firstName = first;
- this.lastName = last;
- this.age = age;
- this.eyeColor = eyecolor;
- this.nationality = "English"
- } //给原型添加属性,必须添加在构造函数里边。原型属性可以拥有原型值(默认值)
- function Person(first, last, age, eyecolor) {
- this.firstName = first;
- this.lastName = last;
- this.age = age;
- this.eyeColor = eyecolor;
- this.name = function() {
- return this.firstName + " " + this.lastName;
- };
- } //添加方法
利用原型属性
js 原型属性允许你去给存在的原型添加新属性和新方法,但要记住:只改变你所拥有的属性,别去动标准 js 对象的属性。
- function Person(first, last, age, eyecolor) {
- this.firstName = first;
- this.lastName = last;
- this.age = age;
- this.eyeColor = eyecolor;
- }
- Person.prototype.nationality = "English";
- Person.prototype.name = function() {
- return this.firstName + " " + this.lastName;
- };
js 函数定义
js 函数可以 function 关键字定义,你也可以用函数声明(declaration)和函数表达式( expression)去定义一个函数。
函数声明
- function functionName(parameters) {
- code to be executed
- }
- //分号被用于分离js执行语句,由于函数声明不是一个可执行语句,因此以分号结束一个函数声明并不常见
函数声明不被立即执行,他们是 "备用",并且当调用时稍后执行。
函数表达式
var z = x(4, 3);// 此时,这个变量可被用作一个函数 // 事实上,上述函数是一个匿名函数,存储在变量中的函数不必拥有名字,他们用变量名调用;并且以分号结束是因为是可执行语句的一部分
- var x = function(a, b) {
- return a * b
- }; //函数表达式可以存储在一个变量里
函数构造器
函数可以利用 js 内嵌的函数构造器 Function()定义
- var myFunction = new Function("a", "b", "return a * b");
- var x = myFunction(4, 3);
事实上你不必如此,在 js 中很不必用到 new 关键字。
函数提升
提升是 js 移动声明到当前作用域顶端的默认行为,提升用于变量声明和函数声明,因此函数可以先调用后声明。但是,函数表达式定义的函数不会被提升。
- myFunction(5); //25
- function myFunction(y) {
- return y * y;
- }
- foo(); //VM747:1 Uncaught TypeError: foo is not a function(…)
- var foo = function() {}
自执行函数
- (function() {
- var x = "Hello!!"; // I will invoke myself
- })();
事实上,上述函数是一个匿名的自执行函数
函数可被用在值中,也可用在表达式中
- function myFunction(a, b) {
- return a * b;
- }
- var x = myFunction(4, 3);
- var y = myFunction(4, 3) * 2;
函数皆对象
typeof 操作符在 js 中对于 functions 返回为'function',但是函数最好是被描述为对象,js 函数拥有属性和方法。
- function myFunction(a, b) {
- return arguments.length;
- } //但函数被调用时返回参数个数
- var txt = myFunction.toString(); //头String()方法返回一个字符串
函数作为一个对象的属性定义,被称作一个对象的方法;
函数作为创造对象的定义,被称作一个对象构造器。
函数形参(parameters)
js 函数对形参值不做任何检查。
js 形参和实参:形参是函数定义中的名(names),实参是传给(或接收)函数的真实值(real values)
- functionName(parameter1, parameter2, parameter3) {
- code to be executed
- }
形参规则:js 针对形参的函数定义不区分数据类型,对传来的实参不做类型检查,对接收的实参数目不做检查。
形参默认:如果函数丢失实参(少于声明的)时调用,缺失的值被设置为:undefined。有时候可以接受,但最好对形参设置一个默认值。
- function myFunction(x, y) {
- if (y === undefined) {
- y = 0;
- }
- } //如果函数被过多实参(多余声明的)调用。这些实参可以利用实参对象获取
实参对象
js 拥有被称作实参对象的内置对象,它们包含一个实参数组,当函数被调用时。此时可以简单利用函数去在一个数据列表中寻找最值。
- x = findMax(1, 123, 500, 115, 44, 88);
- function findMax() {
- var i;
- var max = -Infinity;
- for (i = 0; i < arguments.length; i++) {
- if (arguments[i] > max) {
- max = arguments[i];
- }
- }
- return max;
- }
- //统计输入值之和
- x = sumAll(1, 123, 500, 115, 44, 88);
- function sumAll() {
- var i, sum = 0;
- for (i = 0; i < arguments.length; i++) {
- sum += arguments[i];
- }
- return sum;
- }
按值传递的实参
形参,在函数调用中,就是函数实参;js 实参按值传递,函数仅仅去知道值,而非实参地址。
如果一个函数改变了实参值,不会改变形参的原始值。形参的改变在函数外部不可见(不反映)。
对象按引用传递,js 中对象索引是值,因此,对象表现为按索引传递:如果一个函数改变一个对象的属性,这就改变了原始值。对象属性的改变在函数外部可见(反映)
js 函数调用
四种方式,每种方式以 this 如何初始化为区分。
函数调用:函数代码当定义时不执行,仅当调用时执行。(a JavaScript function can be invoked without being called.)
作为函数调用函数
- function myFunction(a, b) {
- return a * b;
- }
- myFunction(10, 2); // myFunction(10, 2) will return 20
上述函数不属于任何对象,但 js 中有一个默认的全局对象。在 html 中默认的全局对象是 html 页面本身,因此上述函数 "属于"html 页面。在浏览器页面对象是浏览器窗口,上述函数自动变成 window 函数,木 Function 和 window. 没有 Function 是一样的
这是一个常用的调用函数的方式,但并不是好习惯。全局变量,方法,或者函数在全局对象中很容易造成命名冲突和 bug。
全局对象
当一个函数没有拥有者对象而被调用时,this 值变成全局对象。在 web 浏览器中全局对象是 browser window。
- function myFunction() {
- return this;
- }
- myFunction(); // Will return the window object
调用一个作为全局对象的函数,引起让 this 值变为全局对象的后果。因此,用 window 对象作为变量很容易阻塞你的编程。
作为方法调用
作为方法调用
- var myObject = {
- firstName: "John",
- lastName: "Doe",
- fullName: function() {
- return this.firstName + " " + this.lastName;
- }
- }
- myObject.fullName(); // Will return "John Doe"
fullName 方法是一个函数,这个函数属于对象,没有 Object 是该函数的拥有者。被称作 this 的东西,是一个拥有 js 代码的对象,此时的 this 值指向 myObject。
- var myObject = {
- firstName: "John",
- lastName: "Doe",
- fullName: function() {
- return this;
- }
- }
- myObject.fullName(); // Will return [object Object] (the owner object);将函数作为对象的方法来调用,使得this指向对象本身
作为构造函数调用
如果一个函数以前置 new 关键字调用,他就是一个构造器的调用。看起来像创造一个新函数,但是由于 js 函数皆对象,你事实上创造了一个新对象。
- // This is a function constructor:
- function myFunction(arg1, arg2) {
- this.firstName = arg1;
- this.lastName = arg2;
- }
- // This creates a new object
- var x = new myFunction("John", "Doe");
- x.firstName; // Will return "John"
构造器的调用创造了一个新对象,这个新对象继承他的构造器的属性和方法。this 关键字在构造器中没有一个值,但是在构造器被调用时,this 值将是所创造的那个新的对象。
以函数的方法调用
js 中函数皆对象,js 函数拥有属性和方法。call()和 apply() 是 js 的预定义函数方法,都可以调用函数,并且都必须将拥有者对象作为首个形参(调用时)。
- function myFunction(a, b) {
- return a * b;
- }
- myObject = myFunction.call(myObject, 10, 2); // Will return 20
- function myFunction(a, b) {
- return a * b;
- }
- myArray = [10, 2];
- myObject = myFunction.apply(myObject, myArray); // Will also return 20
两种方式均那拥有者对象(owner object)作为首个实参,唯一的区别是 call 分散地取函数实参,apply 将函数实参作为一个数组来取。在 js 严格模式中,被调用的函数中首个实参是 this 的值,即使这个实参不是一个对象。在非严格模式中,如果首个实参是 null 或者 undefined,它将被全局对象取代。利用 call 和 apply 你可以设置 this 值,并且将函数作为一个现有对象的方法调用。
js 闭包
js 变量可以属于全局的或者局部的作用域,局部变量可利用闭包构造。
全局变量
一个函数可以访问定义在其中的所有变量:
- function myFunction() {
- var a = 4;
- return a * a;
- }
并且,一个函数也可以访问在其外层的函数,像这样:
- var a = 4;
- function myFunction() {
- return a * a;
- }
此时 a 是一个全局变量,在页面中全局变量属于 window 对象,全局变量可被所有页面中脚本利用和改变;第一个例子中 a 是局部变量,局部变量仅能在其所定义的函数内部用,对其他函数和脚本代码隐藏。同名的全局和局部变量是不同的变量,改变一个不影响另一个,变量不以 var 关键字声明的通常是全局的,即使在函数内部。
变量生命周期
全局变量和你的应用程序,你的 window,你的 webpage 同生,局部变量短命,当函数调用时被造就,当调用结束被删除。
看以下例子
- var counter = 0;
- function add() {
- counter += 1;
- }
- add();
- add();
- add();
- // the counter is now equal to 3
- function add() {
- var counter = 0;
- counter += 1;
- }
- add();
- add();
- add();
- // the counter should now be 3, but it does not work !
- function add() {
- var counter = 0;
- function plus() {
- counter += 1;
- }
- plus();
- return counter;
- } //solve this problem
js 闭包(closure)
还记得自我调用函数吗?这个函数干嘛的?
- var add = (function() {
- var counter = 0;
- return function() {
- return counter += 1;
- }
- })();
- add();
- add();
- add();
- // the counter is now 3
解释:变量 add 作为一个自我调用函数的返回值声明,自执行函数仅运行一次,设置 counter 为 0,返回表达式。这种方式的 add 变成一个函数,完美的部分是它可以访问父级作用域内的 counter. 这就是所谓的 js 闭包,它让函数拥有私有变量成为可能。counter 被匿名函数的作用域所保护,并且只能利用 add 函数去改变。
总之:闭包是一个即使父级函数关闭,仍可以访问父级作用域的函数。
参考文献:http://www.w3schools.com/
来源: http://www.cnblogs.com/frank26/p/6012104.html