字符串不是对象,为什么具备属性?
只要引用了字符串的属性,JavaScript 就会将字符串通过
new String(str)
的 方式转换成对象,这个对象继承了字符串的方法,并用来处理属性的引用,一旦引用结束,这个创建的对象就会销毁。
同字符串一样,数字和布尔值也具备各自的方法:通过
Number()
和Boolean()
构造函数创建一个临时对象。null和undefined 没有包装
var s = 'test';
s.len = 2;
console.log(s.len); // undefined
当运行的时候,s.len 是undefined,当给s.len 赋值的时候,内部会new String(s); 赋值完毕后会销毁,所以s.len,没有被保留下来
重复的声明和遗漏的声明
使用
var
语句重复声明变量是合法且无害的,如果重复声明带有初始化器,那么就和赋值语句没什么两样。
如果读取一个没有声明的变量的值,js 会报错,在严格模式中,给没声明的变量赋值也会报错。
非严格模式下,给一个为声明的变量赋值,js实际上会给全局对象创建一个同名属性,并且它看起来就像一个全局属性(但不完全一样);
作用域
作用域是变量在代码中定义的区域,全局变量拥有全局作用域,在JavaScript代码中的任何地方都是有定义的。然而在函数内部的变量,它们是局部变量,作用域是局部性的。函数参数也是局部变量,它们只在函数体内有定义。
在函数体内,局部变量的优先级高于同名的全局变量。如果函数体内声明的局部变量或者函数参数变量和全局变量重名,那么全局变量会被局部变量所掩盖。
var scope = "global";
function scope_demo(){
var scope = "function";
return scope;
}
console.log(scope_demo()); //function
在函数体内声明
scope
的时候 ,声明一个局部变量,在函数体内使用scope
会优先调用到局部变量。
变量提升和函数作用域
在一些类似C语言的编程语言中,花括号内的每一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的,我们成为 块级作用域(block scope),在javascript 中没有块级作用域,javascript取而代码的使用了函数作用域(function scope) ,变量在它们的函数体内和嵌套函数体内都是有定义的。
function test(o){
console.log(o,j,i); //o 是实参,j是undefined,i是0
var i = 0;
if(typeof o == 'object'){
var j = 0;
for(var k = 0;k<10;k++){
console.log(k);
}
}
}
test(1);
//输出 1,undefined,undefined; 1是o的实参,j 变量提升,但是值是undefined,i也一样
JavaScript的函数作用域是指在函数内声明的所有变量,在函数体内始终是可见的,有意思的是,在变量声明之前已经可以使用,JavaScript 的这个特性被称为声明提前(变量提升):JavaScript 函数里声明的所有变量(但不涉及赋值)都被提前 函数的顶部
作用域链
JavaScript 是基于词法作用域的语言。全局变量在程序中使用都是有定义的。局部变量在声明它的函数体内以及所嵌套的函数内使用时有定义的。
如果将一个局部变量看做时自定义实现的对象的属性的。那么可以换个角度来解读变量作用域。每一段javascript代码(全局或函数)都有一个与之关联的作用域链(scope chain)。这个作用域链是一个对象或者链表,这组对象定义个这段代码"作用域中"的变量。**当javascript需要查找变量x的值得时候(这个过程叫做"变量解析"),它会从链中的第一个对象开始查找,如果这个对象有名为x的属性,则会直接使用这个属性的值,如果第一个对象不存在x属性,javascript会继续查找链上的下一个对象,直到找到为查找到最后,没有找到,javascript会认为作用域链上不存在x,并抛出一个引用异常。
对象
对象是javascript的基本数据类型。对象是一种复合值,它将很多值聚合在一起。可通过名字访问这些值。对象也可以看做属性的无序集合,每个属性都是一个键值对,属性是字符串。
对象不仅仅是保持字符串到值得映射,除了可以保持自有的属性,javascript 对象还可以从一个称为原型的对象集成属性。这种"原型式继承"式javascript的核心特征。
javascript 对象是动态的,--可以新增也可以删除-- 但它们通常用来模拟静态语言中的 "结构体",有事和会用作字符串的集合
对象最常见的用法是 创建、设置、查找、删除、检测和枚举它的属性。除了名字和值之外,每一个属性还有一些与之相关的值,称为"属性特性":
- 可写(writable attribute),表明是否可以设置该属性的值
- 可枚举(enumerable attribute),表明是否可以通过for/in循环返回该属性。
- 可配置(configurable attrbute) ,表明是否可以删除或修改该属性。
在Ecmascript5之前,通过代码给对象创建的所有属性都是可写的、可枚举的和可配置的。
除了包含属性之外,每个对象还拥有三个相关的对象特性:
- 对象的原型(prototype)指向另一个对象,本对象的属性继承自它的原型对象。
- 对象的类(class)是一个标识对象类型的字符串。
- 对象的拓展标记(extensible flag)知名了是否可以向该对象添加新属性。
三类对象、两类属性:
- 内置对象:数组、函数、日期、正则都是内置对象;
- 宿主对象:由javascript 解释器所嵌入的宿主环境(比如web浏览器)定义的。
- 自定义对象:由javascript 代码创建的对象。
- 自有属性:直接在对象中定义的属性。
- 继承属性:对象 原型链上定义的属性。
对象的创建:
-
对象直接量
创建对象最简单的方式就是在javascript代码中使用对象直接量。
var hello = { a:1, x:2 }
-
通过new 创建对象
new 运算符创建并初始化一个新对象,关键字new后跟随一个函数调用。这里的函数称作构造函数,构造函数泳衣初始化一个新创建的对象。javascript语言中核心的原始类型都包含内置构造函数。例如:
var o = new Object(); //创建一个新对象,和{}一样。 var a = new Array(); //创建空数组,和[]一样。 var d = new Date(); //创建一个当前时间的对象 var r = new RegEx('js'); //创建一个正则对象。
-
理解对象
-
对象属性 (IE8以下不可使用,不建议在IE8使用)
-
Configurable
是否可以用delete
删除 -
Enumerable
是否可以用for-in
循环 -
Writable
是否可以修改,默认true,如果设置为false,在严格模式下修改会报错,非严格模式修改无效 -
Value
值
var Person = {}; Object.defineProperty(Person,"name",{ writable:false, //现在person.name不能被修改 value:"person_name" //默认值 });
-
-
访问器属性
访问器属性不包含数据值,他们包含一堆getter、setter方法(不是必须的),当读取属性时,会调用getter方法,赋值属性会调用setter方法
var Book = { name: 'JavaScript高级程序设计', size2: 1 }; Object.defineProperty(Book, "sizi", { get: function () { return this.name.length; }, set: function (newValue) { //newValue 要赋的值 this.size2 = newValue; } });
支持ES5的这个方法只有IE9+,在这个方法之前,有两个非标准的方法
__defineGetter__
和__defineSetter__
方法
-
- 定义多个属性
- Object.defineProperties();
var book = {}; Object.defineProperties(book, { _year: { value: 2004 }, edition: { value: 1 }, year: { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } } });
网友评论