1.js中基本数据类型?
number string boolean null underfined object(Date、Array、 Function)symbol bigInt
具体情况:
Undefined: 类型表示未定义,它的类型只有一个值,就是 undefined。任何变量在赋值前是
Undefined 类型、值为 undefined
Null: 表示的是:“定义了但是为空”
Boolean :类型有两个值, true 和 false,它用于表示逻辑意义上的真和假,同样有关键字
true 和 false 来表示两个值
String: 用于表示文本数据。String 有最大长度是 2^53 - 1,这在一般开发中都是够用的,
但是有趣的是,这个所谓最大长度,并不完全是你理解中的字符数。因为 String 的意义并非“字符串”
,而是字符串的 UTF16 编码,我们字符串的操作 charAt、charCodeAt、length 等方法针对的都是
UTF16 编码。所以,字符串的最大长度,实际上是受字符串的编码长度影响的。
Number:类型表示我们通常意义上的“数字”,这个数字大致对应数学中的有理数,
Number 类型有 18437736874454810627(即 2^64-2^53+3) 个值,
JavaScript 中的 Number 类型基本符合
IEEE 754-2008 规定的双精度浮点数规则,
但是 JavaScript 为了表达几个额外的语言场景
(比如不让除以 0 出错,而引入了无穷大的概念),规定了几个例外情况:NaN,
占用了9007199254740990,这原本是符合 IEEE 规则的数字;
Infinity,无穷大;-Infinity,
负无穷大。另外,值得注意的是,JavaScript 中有 +0 和 -0,
在加法类运算中它们没有区别,
但是除法的场合则需要特别留意区分,“忘记检测除以 -0,而得到负无穷大”的情况经常会导致错误,
而区分 +0 和 -0 的方式,正是检测 1/x 是 Infinity 还是 -Infinity。根据双精度浮点数的定义,
Number 类型中有效的整数范围是 -0x1fffffffffffff 至 0x1fffffffffffff,
所以 Number 无法精确表示此范围外的整数。
为什么在 JavaScript 中,0.1+0.2 不能 =0.3
所以实际上,这里错误的不是结论,而是比较的方法,正确的比较方法是使用 JavaScript
提供的最小精度值:
console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
检查等式左右两边差的绝对值是否小于最小精度,才是正确的比较浮点数的方法。这段代码结果就是 true 了。
Symbol:是 ES6 中引入的新类型,它是一切非字符串的对象 key 的集合,在 ES6 规范中,
整个对象系统被用 Symbol 重塑
Object :对象的定义是“属性的集合”,属性分为数据属性和访问器属性,二者都是 key-value 结构,
key 可以是字符串或者 Symbol 类型
Number、String 和 Boolean,三个构造器是两用的,当跟 new 搭配时,它们产生对象,
当直接调用时,它们表示强制类型转换。
Symbol 函数比较特殊,直接用 new 调用它会抛出错误,但它仍然是 Symbol 对象的构造器。
2.隐式类型转换
巧妙运用 "+" 与 "-" 规则 转换类型
var nums = "you are good boy" + 11; //转成字符串
var nums = "37" - 7; // 转成number 30
var nums = "37" + 7; // 转成字符串 377
nums - 0 可以转成数字类型
nums + "" 可以转成字符类型
3. == 与 ===
** "==" **
1、"123" == 123
2、0 == false
3、null == undefined
4、new Object() == new Object()
5、[1,2] = [1,2]
6、number == "string" ,"string"转成 number 进行比较 1 == "1.0" // true
7、boolean == ? boolean 转成 number 进行比较 true== 1 false == 0 // true
8、object == number | string 尝试对象转换为基本类型 new String('hi') =='hi' // true
** "===" 类型不同:返回false,类型相同 **
1、null === null
2、undefined === undefined
3、NaN !== NaN
4、new Object() !== new Object()
4.类型检测判断?
** 1. typeof 判断函数对象和基本类型比较方便 数组,null就不行了 记录:**
typeof 100 "number"
typeof true "boolean"
typeof function "function"
typeof (undefined) "undefined"
typeof new Object () "object"
typeof [1,2] "object"
typeof NaN "number"
typeof null "object"
** 2.(对象) instanceof(函数/构造器) 基于原型链去判断数组,适合去判断自定义对象,也可以用来检测原生对象,在不同的iframe 和window 间检测时失效。**
obj instanceof Object
obj 期望是一个对象,如果是基本类型 直接返回false Object 期望是一个函数对象活着函数构造器 ,如果不是抛出异常。
** 补写例子**
[1,2] instanceof Array === true;
** 3. Object.prototype.toString 适合内置对象和基元类型 ,遇到null 和undefined **
Object.prototype.toString.apply([]); === "[object Array]";
Object.prototype.toString.apply(function (){}); === "[object Function]";
Object.prototype.toString.apply(null); === "[object null]";
Object.prototype.toString.apply(undefined); === "[object undefined]";
ie 6/7/8 中
Object.prototype.toString.apply(null); === "[object Object]";
** 4.constructor可以被改写 **
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
constructor(name) {
super(name); // call the super class constructor and pass in the name parameter
}
speak() {
console.log(this.name + ' barks.');
}
}
let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
以上代码创造了 Animal 类,并且通过 extends 关键字让 Dog 继承了它,展示了最终调用子类的 speak 方法获取了父类的 name。比起早期的原型模拟方式,使用 extends 关键字自动设置了 constructor,并且会自动调用父类的构造函数,这是一种更少坑的设计。所以当我们使用类的思想来设计代码时,应该尽量使用 class 来声明类,而不是用旧语法,拿函数来模拟对象。
** 5.duck type ** 判断数组时》判断是否有相似的特征 join push length是不是数字
5、对象的创建 ?
** 1.对象的创建-字面量 **
var obj = {a:1,b:2};
var obj1 = {a:1,b:2, c:{ d:1,e:2}};
** 2.new / 原型链的方式 **
foo.prototype.z = 3;
var obj = new foo();
obj.y = 2;
obj.x = 1;
obj.x // 1
obj.y // 2
obj.z // 3
typeof obj.toString; // 'function'
'z' in obj ; // true 在obj原型上找到z
obj.hasOwnProperty('z'); // false 在当前对象obj上找不到z
obj的 _proto_ 指向 foo.prototype ,foo.prototype的 _proto_ 指向 Object.prototype, Object.prototype 的 _proto_ 指向 null
obj.z = 5;
obj.hasOwnProperty('z') // true
foo.prototype.z // 3
obj.z // 5
obj.z = undefined;
obj.z; // undefined
delect obj.z;
obj.z // 3
** 3.object.create ** 创建一个空对象,对象的原型指向参数
var obj = Object.create({x:1});
obj.x // 1
typeof obj.toString // "function"
obj.hasOwnProperty('x'); //false
** obj -> {x:1} -> object.prototype -> null **
var obj = Object.create(null);
obj.toString // undefined
** obj -> null **
获取实例对象obj的原型对象,有三种方法。
obj.proto
obj.constructor.prototype
Object.getPrototypeOf(obj)
上面三种方法之中,前两种都不是很可靠。 __proto__属性只有浏览器才需要部署,其他环境可以不部署。而obj.constructor.prototype在手动改变原型对象时,可能会失效
创建对象 的4种方式:
var obj1 = Object.create({});
var obj2 = Object.create(Object.prototype);
var obj3 = new Object();
var obj4 = {};
6、 函数的声明 和 函数表达式
** 函数的声明:函数声明可以前置**
function add(){}
** 函数的表达式:**
var add = function (){
}
(function(){
})();
return function(){
};
var add = function foo (a,b){ // 命名函数表达式
}
函数构造器 :
var func = new Function ('a','b','console.log(a+b)); // 只能匿名
func(1,2);
7.this
** 1> 一般函数的this **
function f1(){
return this;
}
f1()===window; // true ,global , object
function f2(){
"use strict";
return this;
}
f2() === undefined; // true
** 2> 作为对象方法的函数的this **
var o = {
prop:37,
f:function(){
return this.prop;
}
}
console.log(o.f()); // 37
var o = {prop:37};
function independent(){
return this.prop;
}
o.f = independent;
console.log(o.f()); // 37
** 3>对象原型链上的this**
var o = {
f:function (){
return this.a+this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 2;
console.log(p.f()); // 5
** 4> get /set 中的this**
** 5> 构造器中的this**
function MyClass(){
this.a = 37;
}
var o = new MyClass();
console.log(o.a) // 37
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // 38
如果没有return返回值,this作为返回值,this对象的原型指向MyClass.prototype的空对象
** 6>call /apply 方法与this**
function add(c,d){
return this.a+this.b+c+d;
}
var o ={a:1,b:2};
add.call(o,6,7); // 1+2+6+7
add.apply(o,[6,7]); // 1+2+6+7
function bar(){
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // "[object Number]"
** 7>bind方法 与this (ie9+才支持)**
function f(){
return this.a;
}
var g = f.bind({a:'test'});
console.log(g()); // test
var o = {a:37,f:f,g:g};
console.log(o.f(),o.g()); // 37 test
** 8>函数属性预留:**
** 9> 闭包 **
** 普通函数:**
function outer(){
var localVal = 30;
return localVal;
}
outer();
** 闭包:**
官方概念:闭包(词法闭包和函数闭包)是指一个函数或函数的引用,与一个引用环境绑定在一起,这个引用环境是一个存储该函数每个非局部变量(也叫自由变量)的表。
闭包,不同于一般的函数,它允许一个函数在立即词法作用域外调用时,仍可访问非本地变量。
优点:灵活方便 封装
缺点:空间浪费 内存泄露 性能消耗
function outer(){
var localVal = 30;
return function (){
return localVal;
};
}
var func = outer();
func();
闭包无处不在:举例:
!funciton (){
var localVal = 'good boy';
document.addEventListener('click',function(){
console.log(localVal);
});
}();
!function(){
var localVal = 'good boy';
var url = 'http://www.baidu.com/';
$ajax({
url:url,
success:function (){
console.log(localVal);
}
})
}();
** 闭包-常见错误之循环闭包 **
错误输出 4 4 4
document.body.innerHTML = "<div id=div1>aaa</div>
<div id=div2>bbb</div><div id=div3>ccc</div>";
for(var i = 0;i < 4; i++){
document.getElementById('div'+i).
addEventListener('click',function(){
alert(i); // all are 4
});
}
如何能输出 1 2 3
document.body.innerHTML = "<div id=div1>aaa</div>
<div id=div2>bbb</div><div id=div3>ccc</div>";
for(var i = 0;i < 4 ;i++){
!function(i){
document.getElementById('div'+i).
addEventListener('click',function(){
alert(i); // 1 2 3
}(i)
}
** 闭包-封装**
(function(){
var _userID = 123;
var _typeID = 'item';
var export = {};
function conver(userID){
return +userID;
};
export.getUserId=function(){
return conver(_userID);
};
export.getTypeId=function(){
return _typeID;
};
window.export=export;
}());
export.getUserId(); // 123
export.getTypeId(); // item
export._userID; // undefined
export._typeID; // undefined
export.conver; // undefined