6种基本数据类型、2种引用类型:
Number,String,Boolean,Null,Undefined,Symbol;Array、Object
用typeof可以检测出变量的基本数据类型,但是有个特例,就是null的typeof返回的是object,这个是javascript的历史Bug;ES6新增数据类型Symbol: 表示独一无二的值;
栈:原始数据类型(Undefined,Null,Boolean,Number、String)
堆:引用数据类型(对象、数组和函数)
内置对象:
- Object
- Number
- String
- Boolean
- Array
- Function
- Date
- RegExp
- Error
- EvalError:代表了一个关于 eval 函数的错误.
- RangeError:值超出范围
- ReferenceError:引用了一个不存在的变量。
- SyntaxError:当JavaScript引擎在解析代码时遇到不符合语言语法的令牌或令牌顺序时,会抛出SyntaxError。
- TypeError:表示值的类型非预期类型
- URIError:全局URI句柄函数使用错误。
var a = 'guojing' console.log(typeof a) 输出:string var b = 311 console.log(typeof b) 输出:number var c = true console.log(typeof c) 输出:boolean var d = [] console.log(typeof d) 输出:object var e = {} console.log(typeof e) 输出:object var f = null console.log(typeof f) 输出:object console.log(typeof g) 输出:undefined
var h = function(){}
console.log(typeof h)
输出:function
1.在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此,它们都会具有对象共有的特点。即:对象具有属性proto,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。
2.方法(Function)方法这个特殊的对象,除了和其他对象一样有上述proto属性之外,还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。
L instanceof R //instanceof运算时,通过判断L的原型链上是否存在R.prototype L.__proto__.__proto__ ..... === R.prototype ? //如果存在返回true 否则返回false
constructor 就是返回对象相对应的构造函数 console.log([].constructor == Array); //true console.log({}.constructor == Object); //true console.log("string".constructor == String); //true console.log((123).constructor == Number); //true console.log(true.constructor == Boolean); //true 注意: 使用instaceof和construcor,被判断的array必须是在当前页面声明的!比如,一个页面(父页面)有一个框架, 框架中引用了一个页面(子页面),在子页面中声明了一个array,并将其赋值给父页面的一个变量, 这时判断该变量,Array == object.constructor;会返回false; 原因: 1、array属于引用型数据,在传递过程中,仅仅是引用地址的传递。 2、每个页面的Array原生对象所引用的地址是不一样的,在子页面声明的array,所对应的构造函数,是子页面的Array对象;父页面来进行判断,使用的Array并不等于子页面的Array。
使用 Object.prototype.toString.call(arr) === '[object Array]' 判断 arr 是否是对象或者数组 function isArray(o) { return Object.prototype.toString.call(o); } var arr=[2,5,6,8]; var obj={name:'zhangsan',age:25}; var fn = function () {} console.log(isArray(arr)); //[object Array] console.log(isArray(obj)); //[object Object] console.log(isArray(fn)); //[object function]
1.一个对象的 __proto__隐式原型 指向构造该对象的构造函数的 prototype原型对象;
2.实例能够访问在构造函数 原型对象prototype 中定义的属性和方法;
3.函数是个特殊的对象,除了和其他对象一样有 隐式原型proto之外,还有自己特有的 原型对象prototype;
4.原型对象prototype 的用途就是包含所有实例共享的属性和方法。
5.原型对象prototype 也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。
6.在js里,万物皆对象;
var A = function(){} var a = new A() console.log(a.__proto__); console.log(A.prototype); 输出:{constructor: ƒ}constructor: ƒ ()__proto__: Object
console.log(a.__proto__.__proto__); console.log(A.prototype.__proto__); console.log(Object.prototype); 输出:{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}constructor: ƒ Object()hasOwnProperty: ƒ hasOwnProperty()isPrototypeOf: ƒ isPrototypeOf()propertyIsEnumerable: ƒ propertyIsEnumerable()toLocaleString: ƒ toLocaleString()toString: ƒ toString()valueOf: ƒ valueOf()__defineGetter__: ƒ __defineGetter__()__defineSetter__: ƒ __defineSetter__()__lookupGetter__: ƒ __lookupGetter__()__lookupSetter__: ƒ __lookupSetter__()get __proto__: ƒ __proto__()set __proto__: ƒ __proto__()arguments: (...)caller: (...)length: 1name: "set __proto__"__proto__: ƒ ()[[Scopes]]: Scopes[0]
console.log(a.__proto__.__proto__.__proto__); console.log(A.prototype.__proto__.__proto__); console.log(Object.prototype.__proto__); 输出:null
通过现代浏览器的操作属性的便利性,可以改变一个对象的 [[Prototype]]
属性, 这种行为在每一个JavaScript引擎和浏览器中都是一个非常慢且影响性能的操作,使用这种方式来改变和继承属性是对性能影响非常严重的,并且性能消耗的时间也不是简单的花费在 obj.__proto__ = ...
语句上, 它还会影响到所有继承来自该 [[Prototype]]
的对象。
如果你关心性能,你就不应该在一个对象中修改它的 [[Prototype]].。相反, 创建一个新的且可以继承 [[Prototype]]
的对象,推荐使用 Object.create()
。
当Object.prototype.__proto__
已被大多数浏览器厂商所支持的今天,其存在和确切行为仅在ECMAScript 2015规范中被标准化为传统功能,以确保Web浏览器的兼容性。为了更好的支持,建议只使用 Object.getPrototypeOf()
。
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__ const person = { isHuman: false, printIntroduction: function () { console.log(`My name is ${this.name}. Am I human?${this.isHuman}`); } }; const me = Object.create(person); me.name = "Matthew"; // "name" is a property set on "me", but not on "person" me.isHuman = true; // 继承的属性可以被覆盖重写
me.printIntroduction(); //expected output: "My name is Matthew. Am I human? true"
Object.getPrototypeOf() 方法返回指定对象的原型
const prototype1 = {}; const object1 = Object.create(prototype1); console.log(Object.getPrototypeOf(object1) === prototype1);
输出:true
console.log(obj1.__proto__ === prototype1);
输出:true
再次理解三种实例化对象的方式:
var a={} console.log(a.__proto__) 输出:{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}constructor: ƒ Object()hasOwnProperty: ƒ hasOwnProperty()isPrototypeOf: ƒ isPrototypeOf()propertyIsEnumerable: ƒ propertyIsEnumerable()toLocaleString: ƒ toLocaleString()toString: ƒ toString()valueOf: ƒ valueOf()__defineGetter__: ƒ __defineGetter__()__defineSetter__: ƒ __defineSetter__()__lookupGetter__: ƒ __lookupGetter__()__lookupSetter__: ƒ __lookupSetter__()get __proto__: ƒ __proto__()set __proto__: ƒ __proto__()
var B = function(){} var b = new B() console.log(b.__proto__) 输出:{constructor: ƒ}
var c = Object.create(a) console.log(c.__proto__) 输出:{}
var d = Object.create(b) console.log(d.__proto__) 输出:B {}